В .NET, какова внутренняя реализация делегата? - PullRequest
18 голосов
/ 10 января 2011

Я понимаю, что объявление делегата выглядит примерно так:

public delegate int PerformCalculation(int x, int y);

Однако должно быть что-то еще. Назначение делегата состоит в том, чтобы предоставить указатель на метод, и для этого вы инкапсулируете ссылку на метод в делегате.

В какой структуре хранится эта ссылка (внутри делегата)? Я также понимаю, что вы можете инкапсулировать ссылку на несколько методов в делегате. Означает ли это, что в делегате есть массив, содержащий их?

Кроме того, какие методы определены в делегате и т. Д. Что на самом деле происходит, когда вы объявляете делегата с помощью краткого:

public delegate int PerformCalculation(int x, int y);

РЕДАКТИРОВАТЬ: Некоторые разъяснения. Когда вы объявляете делегата, компилятор автоматически создает запечатанный класс, который унаследован от System.MulticastDelegate для вас. Вы можете увидеть это, если посмотрите на свою сборку с помощью ildasm. Это аккуратно. По сути, с помощью одного оператора вы получаете целый новый класс, сгенерированный для вас во время компиляции, и он обладает всеми необходимыми вам функциями.

Ответы [ 2 ]

19 голосов
/ 10 января 2011

Внутренне это ссылочный тип, очень похожий на класс. Переписано это выглядит так:

public /* delegate */ class PerformCalculation : MulticastDelegate {
    public PerformCalculation(object target, IntPtr method) {}
    public virtual void Invoke(int x, int y) {}
    public virtual IAsyncResult BeginInvoke(int x, int y, AsyncCallback callback, object state) {}
    public virtual void EndInvoke(IAsyncResult result) {}
}

Я оставил реализации этих элементов пустыми, они фактически сопоставлены с кодом в CLR. Компилятор динамически генерирует сигнатуры методов в зависимости от сигнатуры объявления делегата. Обратите внимание на аргументы x и y. JIT-компилятор помогает вызвать конструктор, используя синтаксис + = или - =, он знает адрес памяти целевого метода делегата. Компилятор автоматически сгенерировал значение аргумента target в зависимости от того, был ли целевой метод статическим или нет. Два аргумента сопоставляются со свойствами (Multicast) Delegate.Target и Method. Фактический экземпляр базового класса может быть либо Delegate, либо MulticastDelegate, в зависимости от того, сколько целей было подписано.

Здесь происходит много секретного соуса.

8 голосов
/ 10 января 2011

Все делегаты наследуются от типа System.Delegate , который содержит Target и Method . Точнее, они наследуются от System.MultiCastDelegate , который наследуется от System.Delegate.

...