2008-09-29 30 views
22

Đây là rõ ràng không phải là xuất hiện như thể đó không phải là phương pháp hay nhất. Ai đó có thể giải thích lý do tại sao nó sẽ không phải là một thực hành tốt nhất hoặc làm thế nào điều này hoạt động? Bất kỳ cuốn sách hoặc bài viết nào cung cấp giải thích sẽ được đánh giá cao.Biến cục bộ với đại biểu

//The constructor 
public Page_Index() { 

    //create a local value 
    string currentValue = "This is the FIRST value"; 

    //use the local variable in a delegate that fires later 
    this.Load += delegate(object sender, EventArgs e) { 
     Response.Write(currentValue); 
    }; 

    //change it again 
    currentValue = "This is the MODIFIED value"; 

} 

Giá trị là đầu ra là giá trị thứ hai "Đã sửa đổi". Phần nào của ma thuật biên dịch là làm công việc này? Điều này đơn giản như theo dõi giá trị trên heap và lấy lại nó sau?

[Chỉnh sửa]: Với một số ý kiến, thay đổi bản án ban đầu một số ...

+0

Không có gì sai với thực hành đó. Nó chỉ là tiên tiến hơn người mới bắt đầu sẽ hiểu. – leppie

+0

được phân bổ; trong thực tế, nó có thể làm cho thiết kế rất sạch sẽ/thanh lịch - nhưng bạn cần phải hiểu những tác động. –

+0

Điều đó thực sự khá thú vị. Tôi sẽ không nghĩ rằng rối tung với các biến địa phương trong phạm vi đại biểu được chỉ định sẽ là thực hành tốt, nhưng bạn học một cái gì đó mới tất cả các thời gian. – Hugoware

Trả lời

27

currentValue không còn là một biến cục bộ: đó là một bắt biến . Đây biên dịch một cái gì đó như:

class Foo { 
    public string currentValue; // yes, it is a field 

    public void SomeMethod(object sender, EventArgs e) { 
    Response.Write(currentValue); 
    } 
} 
... 
public Page_Index() { 
    Foo foo = new Foo(); 
    foo.currentValue = "This is the FIRST value"; 
    this.Load += foo.SomeMethod; 

    foo.currentValue = "This is the MODIFIED value"; 
} 

Jon Skeet có một ghi thực sự tốt lên điều này trong C# in Depth và riêng biệt (không phải là chi tiết) thảo luận here.

Lưu ý rằng biến hiện tạiGiá trị bây giờ là trên đống, không phải là ngăn xếp - điều này có rất nhiều tác động, ít nhất là bây giờ nó có thể được sử dụng bởi những người gọi khác nhau.

Điều này khác với java: trong java giá trị của một biến được ghi lại. Trong C#, biến số chính nó bị bắt.

+0

Cũng như viết nó trong C# trong chiều sâu (cảm ơn cho các plug!), Tôi đã có một bài viết so sánh C# và Java đóng cửa và giải thích lý do tại sao họ đang tốt đẹp: http://csharpindepth.com/Articles/ Chương 5/Closures.aspx –

+0

Ah - khi bạn đang viết bình luận đó, tôi đã chỉnh sửa ở trên để bao gồm nó. Tăng gấp đôi giá trị ;-p –

+0

@Mark: Để cải thiện một chút câu trả lời tuyệt vời của bạn, bạn có thể trao đổi "giá trị * biến *" bằng "* giá trị * của biến" trong câu cuối cùng của bạn không? Vì biến được gọi là "currentValue", nó có thể gây nhầm lẫn cho người đọc (giống như tôi), trước tiên nghĩ rằng "giá trị * nghiêng" đề cập đến * tên * của biến ("biến nào? Giá trị được gọi là * giá trị *") – chiccodoro

0

Bạn cần nắm bắt giá trị của biến trong phạm vi đóng/đại biểu, nếu không nó có thể được sửa đổi, như bạn đã thấy.

Gán currentValue thành biến cục bộ (bên trong) cho đại biểu.

2

Tôi cho rằng nhiều câu hỏi tôi hỏi là làm thế nào là nó làm việc với một biến địa phương [MG chỉnh sửa: "Ack - bỏ qua điều này ..." đã được bổ sung sau]

Đó là điểm; nó thực sự là không phải là một biến địa phương nữa - ít nhất, không phải về mặt chúng ta thường nghĩ về chúng như thế nào (trên ngăn xếp, v.v.). Nó trông giống như một, nhưng nó không phải là.

Và để biết thông tin, hãy "thực hành không tốt" - các phương pháp ẩn danh và các biến bị bắt thực sự là một công cụ cực kỳ mạnh mẽ, đặc biệt là khi làm việc với các sự kiện. Hãy sử dụng chúng, nhưng nếu bạn đang đi xuống con đường này, tôi sẽ khuyên bạn nên chọn cuốn sách của Jon để chắc chắn rằng bạn hiểu những gì đang thực sự xảy ra.