2012-02-25 46 views
11

Tôi đã đọc rằng một loại tham chiếu giữ tham chiếu đến một đối tượng thực tế có thể được lưu trữ trên vùng được quản lý. Khi một phương thức được "gán" cho biến tham chiếu đại biểu, thì tham chiếu trỏ đến bộ nhớ nào? Khối bộ nhớ này phải làm gì với mã chức năng thực tế?Điểm đại biểu là gì?

+0

Không chính xác câu trả lời bạn đang tìm kiếm nhưng bài đăng này có thể cung cấp một số thông tin chi tiết về đại biểu http://stackoverflow.com/questions/527489/how-delegates-work-in-the-background –

Trả lời

14

Hãy tách biệt một ví dụ đơn giản:

using System; 
class Program 
{ 
    delegate bool MyFilter(int x); 

    bool IsOdd(int x) 
    { 
     return x % 2 == 1; 
    } 

    static void Main() 
    { 
     MyFilter f = new Program().IsOdd; 
     Console.WriteLine(f(5)); 
    } 
} 

không trình biên dịch làm gì? Hãy bắt đầu với dòng này:

delegate bool MyFilter(int x); 

Trình biên dịch tạo ra một loại trông hơi như thế này:

class MyFilter : MulticastDelegate 
{ 
    public MyFilter(Object thisRef, IntPtr method); 
    public bool Invoke(int x); 
    // BeginInvoke(), EndInvoke() - Let's ignore those 
}  

Loại MyFilter có một constructor mà chấp nhận hai tham số: một IntPtr cho cơ thể phương pháp để gọi và một đối tượng mà phương thức này cần được gọi. Phương thức Invoke() trên kiểu MyFilter gọi thực thể ủy nhiệm.

Bây giờ, hãy xem điều gì xảy ra trong phương thức Main(). Trình biên dịch sẽ viết lại nó như thế này:

static void Main() 
    { 
     MyFilter f = new MyFilter(new Program(), addressof(Program.IsOdd)); 
     Console.WriteLine(f.Invoke(5)); 
    } 

Tất nhiên, addressof không phải là toán tử C# thực tế, nhưng bạn có thể tưởng tượng nó trả về địa chỉ của phương thức cho phương thức được truyền vào. Ngoài ra, tôi đã không thảo luận về các chủ đề khác liên quan đến các đại biểu như chuỗi (đó là một tính năng được cung cấp bởi lớp cơ sở MulticastDelegate), nhưng hy vọng tôi đã giải quyết câu hỏi của bạn.

Để tóm tắt, tham chiếu đại biểu trỏ đến một đối tượng triển khai phương thức Invoke khớp với chữ ký của đại biểu. Đối tượng theo dõi con trỏ tới phương thức cần được gọi và cũng là đối tượng đích để gọi phương thức (trừ khi phương thức này là tĩnh).

0

Thực tế có hai loại đại biểu, DelegateMulticastDelegate. Đây là các lớp trừu tượng được kế thừa từ trong một phiên bản thực tế của delegate. Tôi khuyên bạn nên đọc các lớp đó vì chúng có nhiều chi tiết hơn (chính xác) hơn tôi đã giải thích ở đây, nhưng đối với phiên bản ngắn:

Mặc dù tôi không chắc chắn 100% cách triển khai hoạt động chính xác, cách dễ nhất suy nghĩ của một đối tượng Delegate đang giữ một objectMethodInfo, là loại phản chiếu cho một phương pháp cụ thể. Lý do loại Delegate là trừu tượng, là vì phương pháp Invoke phụ thuộc vào các tham số của phương pháp.

Tương tự, MulticastDelegate giữ nhiều đối tượng Delegate, mỗi đối tượng trỏ đến kết hợp riêng lẻ object/MethodInfo. Điều này cho phép hệ thống event, trong đó một đơn event được kích hoạt trong nhiều phương thức được gọi.

Trở lại với chi tiết thực hiện, khi bạn định nghĩa một delegate, nó tạo ra một lớp kế thừa từ MulticastDelegate với một phương pháp Invoke, cũng là object có thể null cho các phương pháp tĩnh.

Trên đầu trang này, bạn có các chi tiết cụ thể về cách các đối tượng chuyển giữa các lời gọi, nhưng có thể tôi đã phạm một số sai lầm trong bài đăng này, vì vậy tôi sẽ để nó ở đó.

0

Nếu không đưa ra câu trả lời quá phức tạp, nó sẽ trỏ (thực hiện tham chiếu) đến khối bộ nhớ thực mà phương thức được lưu trữ.

0

Một đại biểu thực sự chứa hai địa chỉ - địa chỉ của phương thức cũng như địa chỉ cho đối tượng. Điều này khá thú vị và một số bằng sáng chế liên quan đến đại biểu đã được trao cho Heljsberg http://www.google.com/patents/US6185728

Đó là hiệu quả cao. Trong một interview, Heljsberg chỉ ra rằng nó có thể hiệu quả hơn VTBL dispatch (vì nó là một con trỏ trực tiếp đến một hàm). Trong trường hợp đơn giản, nó thực sự là một cuộc gọi gián tiếp. ví dụ:

jmp *%eax 

Nhìn chung, phải mất 4 instructions to execute a delegate.

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