2010-10-22 24 views
5

Đã thấy một số câu hỏi tương tự ở đây, nhưng không có câu hỏi nào trong số đó có vẻ là vấn đề của tôi ...Truy cập vào đóng cửa đã sửa đổi ... nhưng tại sao?

Tôi hiểu (hoặc tôi đã hiểu) khái niệm đóng cửa và hiểu điều gì sẽ khiến Người chia sẻ khiếu nại về quyền truy cập vào sửa đổi đóng cửa, nhưng trong đoạn code dưới đây tôi không hiểu làm thế nào tôi vi phạm đóng cửa.

primaryApps được khai báo trong ngữ cảnh của vòng lặp for, primary sẽ không thay đổi trong khi tôi đang xử lý primaryApps. Nếu tôi đã tuyên bố primaryApps bên ngoài vòng lặp for, thì tuyệt đối, tôi có vấn đề về đóng cửa. Nhưng tại sao trong mã dưới đây?

var primaries = (from row in openRequestsDataSet.AppPrimaries 
       select row.User).Distinct(); 

    foreach (string primary in primaries) { 

     // Complains because 'primary' is accessing a modified closure 
     var primaryApps = openRequestsDataSet.AppPrimaries.Select(x => x.User == primary); 

Tính năng chia sẻ lại không đủ thông minh để tìm ra nó không phải là vấn đề, hoặc có lý do gì khiến tôi không thấy?

+1

Bạn có chắc chắn muốn sử dụng 'Chọn' thay vì 'Ở đâu' không? – diceguyd30

+0

Chọn trả về một mảng các hàng dữ liệu đã nhập ... trong đó trả về một IEnumerable của chúng. Hoặc là một người sẽ làm việc cho những gì tôi đang làm; Tôi đã đọc các bài báo nói. Chọn nhanh hơn trong các điều kiện tôi đang sử dụng. Có lẽ nó là, có thể nó không phải là, khó nói. –

+0

Tôi lấy lại nó ... bởi vì tôi có một lambda, tôi không sử dụng datatable.select được xây dựng trong(), vì vậy tôi không nhận được một mảng các hàng đã gõ. Trong trường hợp đó, bạn chính xác, tôi không chuyển đổi các giá trị, vì vậy một nơi có ý nghĩa hơn. –

Trả lời

10

Vấn đề là trong tuyên bố sau

Vì primaryApps được khai báo trong bối cảnh của các vòng lặp for, tiểu học sẽ không thay đổi trong khi tôi đang chế biến primaryApps.

Chỉ đơn giản là không có cách nào để Resharper xác minh điều này 100%. Các lambda tham chiếu đến việc đóng cửa ở đây được chuyển đến hàm bên ngoài ngữ cảnh của vòng lặp này: Phương thức AppPrimaries.Select. Hàm này có thể tự lưu trữ biểu thức đại biểu kết quả, thực thi nó sau và chạy thẳng vào việc nắm bắt vấn đề biến lặp.

Phát hiện đúng cách điều này có thể thực hiện được không và thực sự không đáng để thực hiện. Thay vào đó, ReSharper đang sử dụng tuyến đường an toàn và cảnh báo về khả năng nắm bắt nguy cơ biến lặp.

+0

Để thêm vào đó, trình biên dịch của Visual Basic đưa ra một cảnh báo chính xác tình huống tương tự. Nhóm C# đã xem xét việc áp dụng cảnh báo VB/Resharper, nhưng hoãn lại quyết định cho đến phiên bản tiếp theo. –

+1

@Jonathan shameless plug, đây là một bài viết giải thích thông điệp VB.Net ở độ sâu http://blogs.msdn.com/b/jaredpar/archive/2007/07/26/closures-in-vb-part-5-looping .aspx – JaredPar

+1

Vì vậy, từ những gì bạn và Eric đang nói, vấn đề là 'AppPrimaries.Select()', là tĩnh, có thể lưu trữ lambda trong một biến tĩnh, và một cuộc gọi khác, ví dụ, 'AppPrimaries.CalculateSelectLambda()' sẽ dẫn đến việc thực hiện được hoãn lại cho đến khi vòng lặp ban đầu được hoàn thành. Tại thời điểm đó, 'primary' sẽ giữ bất kỳ giá trị nào được đặt cho lần cuối qua vòng lặp. –

1

Theo như tôi biết Resharper tạo cảnh báo mỗi khi bạn truy cập biến foreach ngay cả khi nó không thực sự gây ra đóng cửa.

+0

Chỉ khi bạn sử dụng biến trong một lambda hoặc bối cảnh thực hiện chậm khác –

0

Có nó chỉ cảnh báo, Look: http://devnet.jetbrains.net/thread/273042

+0

Vâng, tôi biết nó chỉ là một cảnh báo ... chỉ cần biết nếu tôi có thể bỏ qua nó một cách an toàn:) Câu trả lời rõ ràng là 'không' –

8

Vì primaryApps được khai báo trong bối cảnh của các vòng lặp for, tiểu học sẽ không thay đổi trong khi tôi đang chế biến primaryApps. Nếu tôi đã khai báo các ứng dụng chính bên ngoài vòng lặp for, thì tuyệt đối, tôi có vấn đề về đóng cửa. Nhưng tại sao trong mã dưới đây?

Jared là đúng; để chứng minh lý do tại sao kết luận của bạn không theo logic từ tiền đề của bạn, hãy tạo một chương trình khai báo các ứng dụng chính trong ngữ cảnh cho vòng lặp for, vẫn gặp phải vấn đề về biến vòng lặp bị bắt. Đủ dễ dàng để làm điều đó.

static class Extensions 
{ 
    public IEnumerable<int> Select(this IEnumerable<int> items, Func<int, bool> selector) 
    { 
     C.list.Add(selector); 
     return System.Enumerable.Select(items, selector); 
    } 
} 

class C 
{ 
    public static List<Func<int, bool>> list = new List<Func<int, bool>>(); 
    public static void M() 
    { 
     int[] primaries = { 10, 20, 30}; 
     int[] secondaries = { 11, 21, 30}; 

     foreach (int primary in primaries) 
     { 
      var primaryApps = secondaries.Select(x => x == primary); 
      // do something with primaryApps 
     } 
     C.N(); 
    } 
    public static void N() 
    { 
     Console.WriteLine(C.list[0](10)); // true or false? 
    } 
} 

đâu "primaryApps" được khai báo là hoàn toàn không liên quan . Điều duy nhất có liên quan là việc đóng cửa có thể tồn tại trong vòng lặp và do đó, ai đó có thể gọi sau, sai mong đợi rằng biến bị bắt trong quá trình đóng bị bắt bằng giá trị.

Trình chia sẻ lại không có cách nào để biết rằng việc triển khai Chọn cụ thể không loại bỏ bộ chọn cho sau này; trên thực tế, đó chính xác là tất cả những gì trong số họ do. Làm thế nào Resharper được cho là biết rằng chúng xảy ra để stash nó đi ở một nơi mà sẽ không thể truy cập sau này?

+0

Tôi nghĩ bạn có nghĩa là "Resharper", không phải "Reflector";) –

+0

Tôi sẽ nhấn mạnh rằng cảnh báo phải làm với 'primary' được khai báo bên ngoài vòng lặp, thay vì' primaryApps' được khai báo bên trong vòng lặp. – Gabe

Các vấn đề liên quan