Вы имеете в виду делегатов в системе типов .NET или синтаксис делегатов C #? Вы имеете в виду «когда вы используете синтаксис делегата вместо синтаксиса лямбда-выражения» или имеете в виду «когда вы используете делегаты вместо классов / интерфейсов / виртуальных методов / и т. Д.»?
Теперь, когда у нас есть лямбда-выражения и анонимные методы в C #, я гораздо чаще использую делегаты. В C # 1, где всегда приходилось иметь отдельный метод для реализации логики, использование делегата часто не имело смысла. В наши дни я использую делегатов для:
Обработчики событий (для графического интерфейса и др.)
Начальные темы
Обратные вызовы (например, для асинхронных API)
LINQ и аналогичные (List.Find и т. Д.)
В любом другом месте, где я хочу эффективно применить "шаблонный" код с некоторой специализированной логикой внутри (где делегат предоставляет специализацию)
Не уверен, как бы я объяснил это вкратце, чтобы не усложнять ситуацию :) (Возможно, это все равно покрыто обработчиками событий, LINQ и шаблоном!
Джон Скит
1
Ваше первое предложение не имеет особого смысла.
senfo
3
Я знаю, что вы пытаетесь сказать, но мне было бы легче прочитать следующее: «Теперь, когда у нас есть лямбда-выражения и анонимные методы в C #, я гораздо чаще использую делегаты». Я знаю, что придираюсь к мелочам, но мне действительно пришлось прочитать это предложение несколько раз, прежде чем оно стало для меня осмысленным.
senfo
4
+1 за смелость бросить вызов достопочтенному мистеру Скиту ;-)
indra
29
Делегаты очень полезны для многих целей.
Одна из таких целей - использовать их для фильтрации последовательностей данных. В этом случае вы должны использовать делегат предиката, который принимает один аргумент и возвращает истину или ложь в зависимости от реализации самого делегата.
Вот глупый пример - я уверен, что вы можете экстраполировать из этого что-нибудь более полезное:
using System;
using System.Linq;
using System.Collections.Generic;classProgram{staticvoidMain(){List<String> names =newList<String>{"Nicole Hare","Michael Hare","Joe Hare","Sammy Hare","George Washington",};// Here I am passing "inMyFamily" to the "Where" extension method// on my List<String>. The C# compiler automatically creates // a delegate instance for me.IEnumerable<String> myFamily = names.Where(inMyFamily);foreach(String name in myFamily)Console.WriteLine(name);}staticBoolean inMyFamily(String name){return name.EndsWith("Hare");}}
static Boolean inMyFamily(String name)Метод делегата. Где принимает делегата в качестве параметра. Поскольку делегаты являются просто указателями на функции, когда вы передаете имя метода в объект, .Where(delegate)который становится делегатом. Поскольку inMyFamily возвращает логический тип, он фактически считается предикатом. Предикаты - это просто делегаты, возвращающие логические значения.
Лэндон Поч
4
«Предикаты - это просто делегаты, возвращающие логические значения». +1
daehaai 06
@LandonPoch этот комментарий лучше было бы поместить в ответ. я, будучи новичком, не мог понять, где это. Спасибо.
Eakan Gopalakrishnan
@Eakan, я на самом деле не отвечал на главный вопрос (когда вы использовали бы делегатов), поэтому я оставил его как комментарий.
Landon Poch
14
Нашел еще один интересный ответ:
Сотрудник только что задал мне этот вопрос - какой смысл делегатов в .NET? Мой ответ был очень коротким, и он не нашел его в сети: отложить выполнение метода.
Вы можете использовать делегаты для объявления переменных и параметров с функциональным типом.
пример
Рассмотрим модель «заимствования ресурсов». Вы хотите контролировать создание и очистку ресурса, позволяя клиентскому коду «заимствовать» ресурс между ними.
Любой метод, соответствующий этой сигнатуре, может использоваться для создания экземпляра делегата этого типа. В C # 2.0 это можно сделать неявно, просто используя имя метода, а также используя анонимные методы.
Этот метод использует тип как параметр. Обратите внимание на вызов делегата.
publicclassDataProvider{protectedstring _connectionString;publicDataProvider(string psConnectionString ){
_connectionString = psConnectionString;}publicvoidUseReader(string psSELECT,DataReaderUser readerUser ){
using (SqlConnection connection =newSqlConnection( _connectionString ))try{SqlCommand command =newSqlCommand( psSELECT, connection );
connection.Open();SqlDataReader reader = command.ExecuteReader();while( reader.Read())
readerUser( reader );// the delegate is invoked}catch(System.Exception ex ){// handle exceptionthrow ex;}}}
Функцию можно вызвать анонимным методом следующим образом. Обратите внимание, что анонимный метод может использовать переменные, объявленные вне себя. Это очень удобно (хотя пример немного надуманный).
string sTableName ="test";string sQuery ="SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='"+ sTableName +"'";DataProvider.UseReader( sQuery,delegate(System.Data.IDataReader reader ){Console.WriteLine( sTableName +"."+ reader[0]);});
Делегаты часто могут использоваться вместо интерфейса с одним методом, типичным примером этого может быть шаблон наблюдателя. На других языках, если вы хотите получать уведомление о том, что что-то произошло, вы можете определить что-то вроде:
classIObserver{voidNotify(...);}
В C # это чаще всего выражается с помощью событий, где обработчик является делегатом, например:
Я пришел к этому очень поздно, но сегодня у меня возникли проблемы с определением цели делегатов, и я написал две простые программы, которые дают тот же результат, что, как мне кажется, хорошо объясняет их цель.
NoDelegates.cs
using System;publicclassTest{publicconstint MAX_VALUE =255;publicconstint MIN_VALUE =10;publicstaticvoid checkInt(int a){Console.Write("checkInt result of {0}: ", a);if(a < MAX_VALUE && a > MIN_VALUE)Console.WriteLine("max and min value is valid");elseConsole.WriteLine("max and min value is not valid");}publicstaticvoid checkMax(int a){Console.Write("checkMax result of {0}: ", a);if(a < MAX_VALUE)Console.WriteLine("max value is valid");elseConsole.WriteLine("max value is not valid");}publicstaticvoid checkMin(int a){Console.Write("checkMin result of {0}: ", a);if(a > MIN_VALUE)Console.WriteLine("min value is valid");elseConsole.WriteLine("min value is not valid");Console.WriteLine("");}}publicclassDriver{publicstaticvoidMain(string[] args){Test.checkInt(1);Test.checkMax(1);Test.checkMin(1);Test.checkInt(10);Test.checkMax(10);Test.checkMin(10);Test.checkInt(20);Test.checkMax(20);Test.checkMin(20);Test.checkInt(30);Test.checkMax(30);Test.checkMin(30);Test.checkInt(254);Test.checkMax(254);Test.checkMin(254);Test.checkInt(255);Test.checkMax(255);Test.checkMin(255);Test.checkInt(256);Test.checkMax(256);Test.checkMin(256);}}
Delegates.cs
using System;publicdelegatevoidValid(int a);publicclassTest{publicconstint MAX_VALUE =255;publicconstint MIN_VALUE =10;publicstaticvoid checkInt(int a){Console.Write("checkInt result of {0}: ", a);if(a < MAX_VALUE && a > MIN_VALUE)Console.WriteLine("max and min value is valid");elseConsole.WriteLine("max and min value is not valid");}publicstaticvoid checkMax(int a){Console.Write("checkMax result of {0}: ", a);if(a < MAX_VALUE)Console.WriteLine("max value is valid");elseConsole.WriteLine("max value is not valid");}publicstaticvoid checkMin(int a){Console.Write("checkMin result of {0}: ", a);if(a > MIN_VALUE)Console.WriteLine("min value is valid");elseConsole.WriteLine("min value is not valid");Console.WriteLine("");}}publicclassDriver{publicstaticvoidMain(string[] args){Valid v1 =newValid(Test.checkInt);
v1 +=newValid(Test.checkMax);
v1 +=newValid(Test.checkMin);
v1(1);
v1(10);
v1(20);
v1(30);
v1(254);
v1(255);
v1(256);}}
Несколько другое использование - ускорение отражения; то есть вместо использования отражения каждый раз вы можете использовать Delegate.CreateDelegateдля создания (типизированного) делегата методу (a MethodInfo) и вместо этого вызывать этот делегат. Тогда это намного быстрее на вызов, так как проверки уже были выполнены.
С помощью Expressionвы также можете сделать то же самое для создания кода на лету - например, вы можете легко создать оператор, Expressionкоторый представляет оператор + для типа, выбранного во время выполнения (для обеспечения поддержки операторов для универсальных шаблонов, которые язык не предоставляет) ; и вы можете скомпилировать его Expressionв типизированный делегат - работа сделана.
Делегаты используются каждый раз, когда вы используете события - это механизм, по которому они работают.
Кроме того, делегаты очень полезны для таких вещей, как использование запросов LINQ. Например, многие запросы LINQ принимают делегат (часто Func<T,TResult>), который можно использовать для фильтрации.
Пример можно увидеть здесь . У вас есть метод обработки объекта, отвечающий определенным требованиям. Однако вы хотите иметь возможность обрабатывать объект несколькими способами. Вместо того, чтобы создавать отдельные методы, вы можете просто назначить соответствующий метод, обрабатывающий объект, делегату и передать делегат методу, который выбирает объекты. Таким образом, вы можете назначать разные методы одному методу селектора. Я постарался сделать это легко понятным.
Например, у меня может быть приложение форм выигрыша, которое загружает файл. Приложение запускает рабочий поток для загрузки (что предотвращает блокировку графического интерфейса). Рабочий поток использует делегатов для отправки сообщений о состоянии (например, о ходе загрузки) обратно в основную программу, чтобы графический интерфейс мог обновлять строку состояния.
Первая линия использования - заменить шаблон Observer / Observable (события). Вторая, красивая элегантная версия паттерна Стратегия. Можно собрать множество других употреблений, хотя я думаю, более эзотерических, чем эти первые два.
Каждый раз, когда вы хотите инкапсулировать поведение, но вызывать его единообразно. Обработчики событий, функции обратного вызова и т. Д. Вы можете выполнять аналогичные действия, используя интерфейсы и приведение типов, но иногда поведение не обязательно привязано к типу или объекту . Иногда нужно просто инкапсулировать поведение.
Ленивая инициализация параметров! Помимо всех предыдущих ответов (шаблон стратегии, шаблон наблюдателя и т. Д.), Делегаты позволяют вам обрабатывать ленивую инициализацию параметров. Например, предположим, что у вас есть функция Download (), которая занимает довольно много времени и возвращает определенный DownloadedObject. Этот объект используется Хранилищем в зависимости от определенных условий. Обычно вы бы:
storage.Store(conditions,Download(item))
Однако с делегатами (точнее, лямбдами) вы можете сделать следующее, изменив подпись хранилища так, чтобы оно получало Condition и Func <Item, DownloadedObject> и использовать его следующим образом:
storage.Store(conditions,(item)=>Download(item))
Следовательно, хранилище будет оценивать делегата только в случае необходимости, выполняя загрузку в зависимости от условий.
Незначительный момент, но «точнее, лямбды» - вы могли бы сделать то же самое с анонимным методом в C # 2.0, хотя он был бы более подробным: delegate (ItemType item) {[return] Download (item);}
Марк Грейвелл
Конечно, как и LINQ: лямбда-выражения - это не более чем синтаксический сахар для делегатов. Они просто сделали делегатов более доступными.
Сантьяго Палладино,
Лямбда-выражения - это немного больше, чем просто делегаты, поскольку они конвертируются в деревья выражений, а также в делегаты.
Джон Скит,
Ну, лямбды также можно скомпилировать в выражения, которые полностью отличаются от делегатов. Но в вашем примере используется Func <,>, который можно использовать из анонимного метода. Выражения на C # 2.0 было бы крайне болезненно писать.
Насколько мне известно, делегаты можно преобразовать в указатели на функции. Это НАМНОГО облегчает жизнь при взаимодействии с машинным кодом, который принимает указатели на функции, поскольку они могут эффективно быть объектно-ориентированными, даже если исходный программист не предусмотрел для этого никаких условий.
Ответы:
Теперь, когда у нас есть лямбда-выражения и анонимные методы в C #, я гораздо чаще использую делегаты. В C # 1, где всегда приходилось иметь отдельный метод для реализации логики, использование делегата часто не имело смысла. В наши дни я использую делегатов для:
источник
Делегаты очень полезны для многих целей.
Одна из таких целей - использовать их для фильтрации последовательностей данных. В этом случае вы должны использовать делегат предиката, который принимает один аргумент и возвращает истину или ложь в зависимости от реализации самого делегата.
Вот глупый пример - я уверен, что вы можете экстраполировать из этого что-нибудь более полезное:
источник
static Boolean inMyFamily(String name)
Метод делегата. Где принимает делегата в качестве параметра. Поскольку делегаты являются просто указателями на функции, когда вы передаете имя метода в объект,.Where(delegate)
который становится делегатом. Поскольку inMyFamily возвращает логический тип, он фактически считается предикатом. Предикаты - это просто делегаты, возвращающие логические значения.Нашел еще один интересный ответ:
Источник: LosTechies
Так же, как это делает LINQ.
источник
Вы можете использовать делегаты для объявления переменных и параметров с функциональным типом.
пример
Рассмотрим модель «заимствования ресурсов». Вы хотите контролировать создание и очистку ресурса, позволяя клиентскому коду «заимствовать» ресурс между ними.
Это объявляет тип делегата.
Любой метод, соответствующий этой сигнатуре, может использоваться для создания экземпляра делегата этого типа. В C # 2.0 это можно сделать неявно, просто используя имя метода, а также используя анонимные методы.
Этот метод использует тип как параметр. Обратите внимание на вызов делегата.
Функцию можно вызвать анонимным методом следующим образом. Обратите внимание, что анонимный метод может использовать переменные, объявленные вне себя. Это очень удобно (хотя пример немного надуманный).
источник
Делегаты часто могут использоваться вместо интерфейса с одним методом, типичным примером этого может быть шаблон наблюдателя. На других языках, если вы хотите получать уведомление о том, что что-то произошло, вы можете определить что-то вроде:
В C # это чаще всего выражается с помощью событий, где обработчик является делегатом, например:
Еще одно отличное место для использования делегатов, если вам нужно передать предикат в функцию, например, при выборе набора элементов из списка:
Выше приведен пример синтаксиса лямбда, который также можно было бы записать следующим образом:
Еще одно место, где может быть полезно использовать делегаты, - это регистрация заводских функций, например:
Надеюсь, это поможет!
источник
Я пришел к этому очень поздно, но сегодня у меня возникли проблемы с определением цели делегатов, и я написал две простые программы, которые дают тот же результат, что, как мне кажется, хорошо объясняет их цель.
NoDelegates.cs
Delegates.cs
источник
Несколько другое использование - ускорение отражения; то есть вместо использования отражения каждый раз вы можете использовать
Delegate.CreateDelegate
для создания (типизированного) делегата методу (aMethodInfo
) и вместо этого вызывать этот делегат. Тогда это намного быстрее на вызов, так как проверки уже были выполнены.С помощью
Expression
вы также можете сделать то же самое для создания кода на лету - например, вы можете легко создать оператор,Expression
который представляет оператор + для типа, выбранного во время выполнения (для обеспечения поддержки операторов для универсальных шаблонов, которые язык не предоставляет) ; и вы можете скомпилировать егоExpression
в типизированный делегат - работа сделана.источник
Делегаты используются каждый раз, когда вы используете события - это механизм, по которому они работают.
Кроме того, делегаты очень полезны для таких вещей, как использование запросов LINQ. Например, многие запросы LINQ принимают делегат (часто
Func<T,TResult>
), который можно использовать для фильтрации.источник
подписка обработчиков событий на события
источник
Пример можно увидеть здесь . У вас есть метод обработки объекта, отвечающий определенным требованиям. Однако вы хотите иметь возможность обрабатывать объект несколькими способами. Вместо того, чтобы создавать отдельные методы, вы можете просто назначить соответствующий метод, обрабатывающий объект, делегату и передать делегат методу, который выбирает объекты. Таким образом, вы можете назначать разные методы одному методу селектора. Я постарался сделать это легко понятным.
источник
Я использую делегатов для общения с потоками.
Например, у меня может быть приложение форм выигрыша, которое загружает файл. Приложение запускает рабочий поток для загрузки (что предотвращает блокировку графического интерфейса). Рабочий поток использует делегатов для отправки сообщений о состоянии (например, о ходе загрузки) обратно в основную программу, чтобы графический интерфейс мог обновлять строку состояния.
источник
Для обработчика событий
Передать метод в параметрах метода
источник
Первая линия использования - заменить шаблон Observer / Observable (события). Вторая, красивая элегантная версия паттерна Стратегия. Можно собрать множество других употреблений, хотя я думаю, более эзотерических, чем эти первые два.
источник
События, другие любые операции
источник
Каждый раз, когда вы хотите инкапсулировать поведение, но вызывать его единообразно. Обработчики событий, функции обратного вызова и т. Д. Вы можете выполнять аналогичные действия, используя интерфейсы и приведение типов, но иногда поведение не обязательно привязано к типу или объекту . Иногда нужно просто инкапсулировать поведение.
источник
Ленивая инициализация параметров! Помимо всех предыдущих ответов (шаблон стратегии, шаблон наблюдателя и т. Д.), Делегаты позволяют вам обрабатывать ленивую инициализацию параметров. Например, предположим, что у вас есть функция Download (), которая занимает довольно много времени и возвращает определенный DownloadedObject. Этот объект используется Хранилищем в зависимости от определенных условий. Обычно вы бы:
Однако с делегатами (точнее, лямбдами) вы можете сделать следующее, изменив подпись хранилища так, чтобы оно получало Condition и Func <Item, DownloadedObject> и использовать его следующим образом:
Следовательно, хранилище будет оценивать делегата только в случае необходимости, выполняя загрузку в зависимости от условий.
источник
Использование делегатов
источник
Параметр сравнения в In Array.Sort (массив T [], сравнение сравнения), List.Sort (сравнение сравнения) и т. Д.
источник
Насколько мне известно, делегаты можно преобразовать в указатели на функции. Это НАМНОГО облегчает жизнь при взаимодействии с машинным кодом, который принимает указатели на функции, поскольку они могут эффективно быть объектно-ориентированными, даже если исходный программист не предусмотрел для этого никаких условий.
источник
Делегаты используются для вызова метода по ссылке. Например:
источник