Câu trả lời của Eric Lippert thực sự gây ấn tượng. Tuy nhiên nó sẽ là tốt đẹp để xây dựng một hình ảnh về cách ngăn xếp khung và chụp công việc nói chung. Để làm điều này, nó giúp xem xét một ví dụ phức tạp hơn một chút.
Đây là mã chụp:
public class Scorekeeper {
int swish = 7;
public Action Counter(int start)
{
int count = 0;
Action counter =() => { count += start + swish; }
return counter;
}
}
Và đây là những gì tôi nghĩ là tương đương sẽ là (nếu chúng ta may mắn Eric Lippert sẽ bình luận về việc liệu đây là thực sự đúng hay không):
private class Locals
{
public Locals(Scorekeeper sk, int st)
{
this.scorekeeper = sk;
this.start = st;
}
private Scorekeeper scorekeeper;
private int start;
public int count;
public void Anonymous()
{
this.count += start + scorekeeper.swish;
}
}
public class Scorekeeper {
int swish = 7;
public Action Counter(int start)
{
Locals locals = new Locals(this, start);
locals.count = 0;
Action counter = new Action(locals.Anonymous);
return counter;
}
}
Vấn đề là lớp địa phương thay thế cho toàn bộ khung ngăn xếp và được khởi tạo cho phù hợp mỗi lần phương thức Counter được gọi. Thông thường khung stack bao gồm một tham chiếu đến 'this', cộng với các đối số phương thức, cộng với các biến cục bộ. (Khung ngăn xếp cũng có hiệu lực mở rộng khi một khối điều khiển được nhập vào.)
Do đó, chúng tôi không chỉ có một đối tượng tương ứng với ngữ cảnh đã chụp, thay vào đó chúng tôi thực sự có một đối tượng trên mỗi khung ngăn xếp được chụp.
Dựa trên điều này, chúng ta có thể sử dụng mô hình tinh thần sau: khung ngăn xếp được lưu trữ trên heap (thay vì trên ngăn xếp), trong khi ngăn xếp chính nó chỉ chứa các con trỏ đến khung ngăn xếp trên đống. Các phương thức Lambda chứa một con trỏ tới khung ngăn xếp. Điều này được thực hiện bằng cách sử dụng bộ nhớ được quản lý, do đó, khung sẽ di chuyển xung quanh trên heap cho đến khi nó không còn cần thiết nữa.
Rõ ràng trình biên dịch có thể thực hiện điều này bằng cách chỉ sử dụng vùng heap khi đối tượng heap được yêu cầu để hỗ trợ đóng cửa lambda.
Điều tôi thích về mô hình này là nó cung cấp hình ảnh tích hợp cho 'lợi tức lãi'. Chúng ta có thể nghĩ về một phương thức iterator (sử dụng return yield) như thể đó là stack frame được tạo trên heap và con trỏ tham chiếu được lưu trữ trong một biến cục bộ trong người gọi, để sử dụng trong quá trình lặp.
Câu hỏi hay. Tôi không chắc chắn, nhưng có, bạn có thể giữ khung ngăn xếp xung quanh trong C#. Máy phát điện sử dụng nó tất cả các thời gian (điều LINQ cho cấu trúc dữ liệu) mà dựa vào năng suất dưới mui xe. Hy vọng rằng tôi không được đánh dấu. nếu tôi, tôi sẽ học rất nhiều. –
sản lượng biến phương pháp thành một lớp riêng biệt với một máy trạng thái. Ngăn xếp chính nó không được giữ xung quanh, nhưng trạng thái ngăn xếp được chuyển vào trạng thái lớp trong một lớp biên dịch được tạo ra bởi trình biên dịch – thecoop
@thecoop, bạn có một liên kết giải thích điều này không? –