Truy cập để đóng cửa sửa đổi


316
string [] files = new string[2];
files[0] = "ThinkFarAhead.Example.Settings.Configuration_Local.xml";
files[1] = "ThinkFarAhead.Example.Settings.Configuration_Global.xml";

//Resharper complains this is an "access to modified closure"
for (int i = 0; i < files.Length; i++ )
{
    // Resharper disable AccessToModifiedClosure
    if(Array.Exists(Assembly.GetExecutingAssembly().GetManifestResourceNames(),
    delegate(string name) { return name.Equals(files[i]); }))
         return Assembly.GetExecutingAssembly().GetManifestResourceStream(files[i]);
    // ReSharper restore AccessToModifiedClosure
}

Ở trên có vẻ hoạt động tốt mặc dù ReSharper phàn nàn rằng đây là "quyền truy cập để đóng cửa sửa đổi". Bất cứ ai có thể làm sáng tỏ về điều này?

(chủ đề này tiếp tục ở đây )


6
Link là ra, nhưng tôi tìm thấy nó ở WebArchive: web.archive.org/web/20150326104221/http://www.jarloo.com/...
Eric Wu

Câu trả lời:


314

Trong trường hợp này, không sao, vì bạn thực sự đang thực thi ủy nhiệm trong vòng lặp.

Tuy nhiên, nếu bạn đã lưu đại biểu và sử dụng nó sau này, bạn sẽ thấy rằng tất cả các đại biểu sẽ đưa ra ngoại lệ khi cố gắng truy cập các tệp [i] - họ đang nắm bắt biến i thay vì giá trị của nó tại thời điểm của đại biểu sự sáng tạo.

Nói tóm lại, đó là một cái gì đó để nhận thức được như một cái bẫy tiềm năng , nhưng trong trường hợp này nó không làm tổn thương bạn.

Xem dưới cùng của trang này để biết ví dụ phức tạp hơn trong đó các kết quả là phản trực giác.


29

Tôi biết đây là một câu hỏi cũ, nhưng gần đây tôi đã nghiên cứu về việc đóng cửa và nghĩ rằng một mẫu mã có thể hữu ích. Đằng sau hậu trường, trình biên dịch đang tạo ra một lớp đại diện cho việc đóng từ vựng cho lệnh gọi hàm của bạn. Nó có thể trông giống như:

private sealed class Closure
{
    public string[] files;
    public int i;

    public bool YourAnonymousMethod(string name)
    {
        return name.Equals(this.files[this.i]);
    }
}

Như đã đề cập ở trên, chức năng của bạn hoạt động vì các vị từ được gọi ngay sau khi tạo. Trình biên dịch sẽ tạo ra một cái gì đó như:

private string Works()
{
    var closure = new Closure();

    closure.files = new string[3];
    closure.files[0] = "notfoo";
    closure.files[1] = "bar";
    closure.files[2] = "notbaz";

    var arrayToSearch = new string[] { "foo", "bar", "baz" };

    //this works, because the predicates are being executed during the loop
    for (closure.i = 0; closure.i < closure.files.Length; closure.i++)
    {
        if (Array.Exists(arrayToSearch, closure.YourAnonymousMethod))
            return closure.files[closure.i];
    }

    return null;
}

Mặt khác, nếu bạn lưu trữ và sau đó gọi các biến vị ngữ, bạn sẽ thấy rằng mọi lệnh gọi đến các biến vị ngữ sẽ thực sự gọi cùng một phương thức trên cùng một thể hiện của lớp đóng và do đó sẽ sử dụng cùng một giá trị cho Tôi.


4

"Tệp" là một biến ngoài được chụp bởi vì nó đã được bắt bởi hàm ủy nhiệm ẩn danh. Tuổi thọ của nó được kéo dài bởi chức năng đại biểu ẩn danh.

Các biến ngoài được bắt giữ Khi một biến ngoài được tham chiếu bởi một hàm ẩn danh, biến ngoài được cho là đã bị bắt bởi hàm ẩn danh. Thông thường, thời gian tồn tại của một biến cục bộ được giới hạn trong việc thực thi khối hoặc câu lệnh mà nó được liên kết (Biến cục bộ). Tuy nhiên, thời gian tồn tại của một biến ngoài bị bắt được kéo dài ít nhất cho đến khi cây đại biểu hoặc cây biểu thức được tạo từ hàm ẩn danh trở thành đủ điều kiện để thu gom rác.

Biến ngoài trên MSDN

Khi một biến cục bộ hoặc một tham số giá trị được bắt bởi một hàm ẩn danh, biến cục bộ hoặc tham số không còn được coi là biến cố định (Biến cố định và di chuyển), mà thay vào đó được coi là biến di chuyển. Do đó, bất kỳ mã không an toàn nào lấy địa chỉ của biến ngoài bị bắt trước tiên phải sử dụng câu lệnh cố định để sửa biến. Lưu ý rằng không giống như một biến không được đánh dấu, một biến cục bộ bị bắt có thể được hiển thị đồng thời với nhiều luồng thực thi.

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.