Riyasktr Ответов: 3

Делегаты и обычные методы


На самом деле я хочу знать, что такое делегат.

Я ищу и читаю так много статей из интернета и все они говорят об этом ДЕЛЕГАТ ИСПОЛЬЗУЕТСЯ ДЛЯ УКАЗАНИЯ НА МЕТОД.

Мне нужны следующие вопросы о делегатах.

1. Если я объявляю метод в классе, например.
public Class Message
{
   public void Show(string Msg)
   {
    //Todo
   }
}


Я хочу знать, в чем заключается основное различие и преимущество вызова этого метода через объект этого класса и через делегат и в чем заключается его выгода.

Если я могу вызвать этот метод как обычный метод

Сообщение сообщение = новый сообщение();
сообщение.Показать("");

public delegate void MsgDelegate(string Msg);

MsgDelegate ObjMsg;

ObjMsg + = Показать();
ObjMsg ("");


ПОЭТОМУ Я ХОЧУ ЗНАТЬ, В ЧЕМ РАЗНИЦА МЕЖДУ ЭТИМИ ДВУМЯ ВЫЗОВАМИ
ОБЫЧНЫЙ ВЫЗОВ МЕТОДА И ВЫЗОВ ДЕЛЕГАТА.







С уважением
Рияс К

3 Ответов

Рейтинг:
26

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[^].

—СА


Wonde Tadesse

5+. превосходный ответ

Sergey Alexandrovich Kryukov

Большое вам спасибо, Вонде.
--СА

ProEnggSoft

Исчерпывающий ответ. +5

Sergey Alexandrovich Kryukov

Спасибо.
--СА

Рейтинг:
2

Clifford Nelson

Может быть, это поможет.

В случае, о котором вы говорите, вы отправляете сообщение в MessageBox. Делегат, который вы могли бы определить для этого, является:

public delegage void Msg(string s);


Теперь вы можете определить некоторые методы, которые имеют эту сигнатуру:

private void MsgBox (string s)
{
  MessageBox.Show (s);
}

private void MsgConsole (string s)
{
  Console.WriteLine (s);
}

private void MsgOutput(string s)
{
  Debug.Print(s)
}

Теперь в вашей программе вы можете иметь переменную, которая определяется как

private Msg SendToRightOutput;


тогда в каком-то методе вы можете:

SendToRightOutput(s);


Теперь вы можете выбрать, куда идет вывод в одном месте, и каждый метод, который использует SendToRightOutput автоматически отправит вывод в нужное место. Еще одна приятная вещь заключается в том, что вы можете назначить несколько мест для отправки выходных данных. То, как вы присваиваете значение SendToRightOutput переменная есть:

SendToRightOutput += MsgConsole;

Надеюсь, это прояснит ситуацию.


Рейтинг:
1

fjdiewornncalwe

Для начала, чтобы лучше понять делегатов, вам следует прочитать Документация MSDN[^] на эту тему. Примеры на этой странице дают очень четкое представление о том, для чего на самом деле существует делегат.


Sergey Alexandrovich Kryukov

К сожалению, слишком много вещей осталось необъясненными за этой статьей и, я думаю, всей документацией Microsoft.
Если вы так не считаете, пожалуйста, посмотрите на мой ответ.
Все мои утверждения можно проверить экспериментально, если хотите.
--СА