Sergey Alexandrovich Kryukov
Это не так просто объяснить сразу. И да, большинство статей, которые я когда-либо видел, неудовлетворительны.
Во-первых, вы не должны перепутать тип делегата и делегировать экземпляры Отношения между ними сильно отличаются от отношений между другими пользовательскими типами и экземплярами.
Тип делегата, определенный сигнатурой метода с помощью, может служить в качестве метода-обработчика, который может быть добавлен в список вызовов экземпляра делегата, например
delegate uint StringHandler(string value, int index);
Теперь давайте определим индекс делегата:
StringHandler stringHandler;
Теперь возникает вопрос: что это за тип
stringHandler
? Это
StringHandler
?
Это-сюрприз! - слушайте внимательно, будьте внимательны;
это не так!
Это легко выяснить, но вы можете сделать это только в том случае, если добавите в экземпляр какой-нибудь обработчик; прежде чем вы это сделаете, этот объект всегда будет равен нулю. Хорошо, давайте сделаем это:
stringHandler = (value, index) => {
if (value.IsNullOrEmpty)
return 0;
else
return value.Length - index; // no matter what; this is just an example
};
Для C# V. 2 вы не можете использовать лямбда-синтаксис или вывод типов, поэтому синтаксис будет немного длиннее:
stringHandler = delegate(string value, int index) { /* ... */ }
Теперь вы можете получить тип экземпляра во время выполнения:
System.Type delegateInstanceType = stringHandler.GetType();
Исследуйте этот тип; и вы увидите, что это тип, который не имеет ничего общего с
StringHandler
Вы узнаете, что это ... класс, производный от
System.Delegate
Пожалуйста, смотрите:
http://msdn.microsoft.com/en-us/library/system.delegate.aspx[
^].
У него много членов, но вы обнаружите, что у него есть член, представляющий его
список вызовов:
GetInvocationList
:
http://msdn.microsoft.com/en-us/library/system.delegate.getinvocationlist.aspx[
^].
Члены списка ... также являются экземплярами делегатов. Рекурсия в действии? Не совсем. Список имеет интересную функциональность: это
квартира Его член не может быть нулевым, и его член никогда не является многоадресным.
Так,
что делает экземпляр делегата вызываемым? Это похоже на метод, потому что он может быть вызван с помощью метода
Invoke
, который вызывает все элементы списка вызовов. Хорошо, но что делает эти методы вызываемыми? По существу, они указывают на две вещи: во-первых, это
адрес вызываемого метода Во-вторых, если метод является экземпляром (нестатическим методом), то экземпляр делегата должен
сохраните ссылку на экземпляр некоторого типа, который будет передан как "this" методу экземпляра Именно это и происходит. Обработчик, добавленный с помощью'+=', может иметь вид
instance.Method
или
type.Method
В первом случае ссылка на экземпляр передается в список вызовов; во втором случае-это случай статического метода, ссылка на экземпляр не используется. Когда происходит вызов делегата, сохраненная ссылка на экземпляр передается вызываемому методу в качестве неявного параметра "this".
Действительно ли список вызовов растет при добавлении другого обработчика? Опять сюрприз:
это не (!). Экземпляры делегатов являются
неизменный Когда применяется оператор'+=', создается совершенно новый экземпляр делегата с более длинным списком вызовов. В результате переменная, представляющая экземпляр делегата, теряет свое значение.
референтная идентичность Одной из причин такой архитектуры является улучшение многопоточности.
Эта тема описана в разделе 4.1 статьи
Диспетчер Динамических Методов[
^].
Дополнительные сведения о статических методах и методах экземпляров см. В моем предыдущем ответе:
Что делает статические методы доступными?[
^].
Я думаю, что следующий вопрос будет о событии… Чтобы немного заинтриговать вас, пожалуйста, посмотрите этот вопрос и мой ответ:
Поскольку у нас есть многоадресные делегаты, зачем нам нужны события?[
^].
В принципе, делегаты - это механизм введения
первоклассные функции в сетях. Пожалуйста, смотрите:
http://en.wikipedia.org/wiki/First-class_function[
^].
В частности, экземпляр делегата может быть передан в качестве параметров другим методам, которые используются для абстрагирования алгоритмов. Это одна из их главных особенностей
функциональное программирование Пожалуйста, смотрите:
http://en.wikipedia.org/wiki/Functional_programming[
^].
—СА