Có bất kỳ tác dụng phụ nào của việc trả về từ bên trong câu lệnh using () không?


125

Trả về một giá trị phương thức từ bên trong một câu lệnh sử dụng có được DataContext dường như luôn hoạt động tốt , như thế này:

public static Transaction GetMostRecentTransaction(int singleId)
{
    using (var db = new DataClasses1DataContext())
    {
        var transaction = (from t in db.Transactions
                              orderby t.WhenCreated descending
                              where t.Id == singleId
                              select t).SingleOrDefault();
        return transaction;
    }
}

Nhưng tôi luôn cảm thấy mình nên đóng một cái gì đó trước khi thoát ra khỏi dấu ngoặc bằng cách sử dụng dấu ngoặc, ví dụ: bằng cách xác định giao dịch trước câu lệnh sử dụng, lấy giá trị của nó trong dấu ngoặc và sau đó quay lại sau dấu ngoặc.

Việc xác định và trả về biến bên ngoài dấu ngoặc sử dụng sẽ được thực hành tốt hơn hoặc bảo tồn tài nguyên theo bất kỳ cách nào?


1
Thật thú vị khi xem xét IL chung cho các biến thể của điều này. Tôi nghi ngờ rằng sẽ có rất ít sự khác biệt trong IL được tạo ra. Tôi thường không thèm khai báo giao dịch var - chỉ cần trả về kết quả của biểu thức.
Jones

Câu trả lời:


164

Không, tôi nghĩ nó rõ ràng hơn theo cách này. Đừng lo lắng, Disposevẫn sẽ được gọi là "trên đường ra" - và chỉ sau khi giá trị trả về được đánh giá đầy đủ. Nếu một ngoại lệ được ném tại bất kỳ điểm nào (bao gồm cả việc đánh giá giá trị trả về) Disposevẫn sẽ được gọi.

Mặc dù bạn chắc chắn có thể đi tuyến đường dài hơn, nhưng đó là hai dòng bổ sung chỉ cần thêm hành trình và bối cảnh bổ sung để theo dõi (về mặt tinh thần). Trên thực tế, bạn không thực sự cần thêm biến cục bộ - mặc dù nó có thể hữu ích về mặt gỡ lỗi. Bạn chỉ có thể có:

public static Transaction GetMostRecentTransaction(int singleId)
{
    using (var db = new DataClasses1DataContext())
    {
        return (from t in db.Transactions
                orderby t.WhenCreated descending
                where t.Id == singleId
                select t).SingleOrDefault();
    }
}

Thật vậy, tôi thậm chí có thể bị cám dỗ sử dụng ký hiệu dấu chấm và đặt Wheređiều kiện trong SingleOrDefault:

public static Transaction GetMostRecentTransaction(int singleId)
{
    using (var db = new DataClasses1DataContext())
    {
        return db.Transactions.OrderByDescending(t => t.WhenCreated)
                              .SingleOrDefault(t => t.Id == singleId);
    }
}

2
Sine là bạn @jon, vẫn an toàn nếu một ngoại lệ được ném vào bên trong khối sử dụng?
Dave Archer

6
Đúng. sử dụng chỉ đơn giản là đường cú pháp cho một lần thử / cuối cùng xây dựng
Mitch Wheat

@David: Như Mitch nói, thật tốt - Tôi đã cập nhật câu trả lời để làm cho nó rõ ràng hơn :)
Jon Skeet

2
Tại sao nên sử dụng OrderByDesceinating kết hợp với SingleOrDefault?
erikkallen

2
@erikkallen: Thật không may, LINQ không có "MaxBy" - vì vậy bạn không thể có được hàng với giá trị tối đa. Đối với LINQ to Object, bạn có thể tự viết một cách khá dễ dàng, nhưng tôi không chắc chắn về cách làm tốt hơn trong trường hợp này. Bạn sẽ đề nghị gì thay thế?
Jon Skeet

32

Có một cái nhìn tại đây

Hiểu câu lệnh 'bằng cách sử dụng' trong C #

CLR chuyển đổi mã của bạn thành MSIL. Và câu lệnh sử dụng được dịch thành một khối thử và cuối cùng. Đây là cách sử dụng câu lệnh được trình bày trong IL. Một tuyên bố sử dụng được dịch thành ba phần: mua lại, sử dụng và xử lý. Tài nguyên được thu nhận đầu tiên, sau đó việc sử dụng được đặt trong một câu lệnh thử với mệnh đề cuối cùng. Đối tượng sau đó được xử lý trong mệnh đề cuối cùng.


4
Một cái nhìn sâu sắc thú vị. Cảm ơn.
Kangkan

1
Điều đó chuyển câu hỏi thành: Bất kỳ tác dụng phụ nào của việc trở về từ khối thử của cuối cùng?
Henk Holterman

3
Không, cuối cùng sẽ luôn được gọi. techinterviews.com/interview-questions-for-c-developers
Adriaan Stander

6

Không tác dụng phụ của việc trở lại từ bên trong một using()tuyên bố.

Cho dù nó làm cho mã dễ đọc nhất là một cuộc thảo luận khác.


0

Tôi nghĩ rằng, tất cả đều giống nhau. Không có gì xấu trong mã. .NET framework sẽ không quan tâm nơi đối tượng được tạo. Điều quan trọng là nó có được tham chiếu hay không.


-1

Vâng, có thể có một tác dụng phụ. Ví dụ: nếu bạn sử dụng cùng một kỹ thuật trong phương thức ASP.NET MVC Action, bạn sẽ gặp lỗi sau: "Đối tượng ObjectContext đã bị loại bỏ và không còn có thể được sử dụng cho các hoạt động yêu cầu kết nối"

public ActionResult GetMostRecentTransaction(int singleId)
{
    using (var db = new DataClasses1DataContext())
    {
        var transaction = (from t in db.Transactions
                              orderby t.WhenCreated descending
                              where t.Id == singleId
                              select t).SingleOrDefault();
        return PartialView("_transactionPartial", transaction);
    }
}

2
nếu bạn xác định giao dịch bên ngoài sử dụng câu lệnh, bạn sẽ gặp lỗi tương tự. sử dụng từ khóa không liên quan trong trường hợp này.
Costa
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.