Как вы используете делегаты в C #?
Как вы используете делегаты в C #?
Ответы:
Теперь, когда у нас есть лямбда-выражения и анонимные методы в C #, я гораздо чаще использую делегаты. В C # 1, где всегда приходилось иметь отдельный метод для реализации логики, использование делегата часто не имело смысла. В наши дни я использую делегатов для:
Делегаты очень полезны для многих целей.
Одна из таких целей - использовать их для фильтрации последовательностей данных. В этом случае вы должны использовать делегат предиката, который принимает один аргумент и возвращает истину или ложь в зависимости от реализации самого делегата.
Вот глупый пример - я уверен, что вы можете экстраполировать из этого что-нибудь более полезное:
using System;
using System.Linq;
using System.Collections.Generic;
class Program
{
static void Main()
{
List<String> names = new List<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);
}
static Boolean inMyFamily(String name)
{
return name.EndsWith("Hare");
}
}
static Boolean inMyFamily(String name)
Метод делегата. Где принимает делегата в качестве параметра. Поскольку делегаты являются просто указателями на функции, когда вы передаете имя метода в объект, .Where(delegate)
который становится делегатом. Поскольку inMyFamily возвращает логический тип, он фактически считается предикатом. Предикаты - это просто делегаты, возвращающие логические значения.
Нашел еще один интересный ответ:
Сотрудник только что задал мне этот вопрос - какой смысл делегатов в .NET? Мой ответ был очень коротким, и он не нашел его в сети: отложить выполнение метода.
Источник: LosTechies
Так же, как это делает LINQ.
Вы можете использовать делегаты для объявления переменных и параметров с функциональным типом.
пример
Рассмотрим модель «заимствования ресурсов». Вы хотите контролировать создание и очистку ресурса, позволяя клиентскому коду «заимствовать» ресурс между ними.
Это объявляет тип делегата.
public delegate void DataReaderUser( System.Data.IDataReader dataReader );
Любой метод, соответствующий этой сигнатуре, может использоваться для создания экземпляра делегата этого типа. В C # 2.0 это можно сделать неявно, просто используя имя метода, а также используя анонимные методы.
Этот метод использует тип как параметр. Обратите внимание на вызов делегата.
public class DataProvider
{
protected string _connectionString;
public DataProvider( string psConnectionString )
{
_connectionString = psConnectionString;
}
public void UseReader( string psSELECT, DataReaderUser readerUser )
{
using ( SqlConnection connection = new SqlConnection( _connectionString ) )
try
{
SqlCommand command = new SqlCommand( psSELECT, connection );
connection.Open();
SqlDataReader reader = command.ExecuteReader();
while ( reader.Read() )
readerUser( reader ); // the delegate is invoked
}
catch ( System.Exception ex )
{
// handle exception
throw 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] );
} );
Делегаты часто могут использоваться вместо интерфейса с одним методом, типичным примером этого может быть шаблон наблюдателя. На других языках, если вы хотите получать уведомление о том, что что-то произошло, вы можете определить что-то вроде:
class IObserver{ void Notify(...); }
В C # это чаще всего выражается с помощью событий, где обработчик является делегатом, например:
myObject.SomeEvent += delegate{ Console.WriteLine("..."); };
Еще одно отличное место для использования делегатов, если вам нужно передать предикат в функцию, например, при выборе набора элементов из списка:
myList.Where(i => i > 10);
Выше приведен пример синтаксиса лямбда, который также можно было бы записать следующим образом:
myList.Where(delegate(int i){ return i > 10; });
Еще одно место, где может быть полезно использовать делегаты, - это регистрация заводских функций, например:
myFactory.RegisterFactory(Widgets.Foo, () => new FooWidget());
var widget = myFactory.BuildWidget(Widgets.Foo);
Надеюсь, это поможет!
Я пришел к этому очень поздно, но сегодня у меня возникли проблемы с определением цели делегатов, и я написал две простые программы, которые дают тот же результат, что, как мне кажется, хорошо объясняет их цель.
NoDelegates.cs
using System;
public class Test {
public const int MAX_VALUE = 255;
public const int MIN_VALUE = 10;
public static void 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");
else
Console.WriteLine("max and min value is not valid");
}
public static void checkMax(int a) {
Console.Write("checkMax result of {0}: ", a);
if (a < MAX_VALUE)
Console.WriteLine("max value is valid");
else
Console.WriteLine("max value is not valid");
}
public static void checkMin(int a) {
Console.Write("checkMin result of {0}: ", a);
if (a > MIN_VALUE)
Console.WriteLine("min value is valid");
else
Console.WriteLine("min value is not valid");
Console.WriteLine("");
}
}
public class Driver {
public static void Main(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;
public delegate void Valid(int a);
public class Test {
public const int MAX_VALUE = 255;
public const int MIN_VALUE = 10;
public static void 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");
else
Console.WriteLine("max and min value is not valid");
}
public static void checkMax(int a) {
Console.Write("checkMax result of {0}: ", a);
if (a < MAX_VALUE)
Console.WriteLine("max value is valid");
else
Console.WriteLine("max value is not valid");
}
public static void checkMin(int a) {
Console.Write("checkMin result of {0}: ", a);
if (a > MIN_VALUE)
Console.WriteLine("min value is valid");
else
Console.WriteLine("min value is not valid");
Console.WriteLine("");
}
}
public class Driver {
public static void Main(string [] args) {
Valid v1 = new Valid(Test.checkInt);
v1 += new Valid(Test.checkMax);
v1 += new Valid(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>
), который можно использовать для фильтрации.
Пример можно увидеть здесь . У вас есть метод обработки объекта, отвечающий определенным требованиям. Однако вы хотите иметь возможность обрабатывать объект несколькими способами. Вместо того, чтобы создавать отдельные методы, вы можете просто назначить соответствующий метод, обрабатывающий объект, делегату и передать делегат методу, который выбирает объекты. Таким образом, вы можете назначать разные методы одному методу селектора. Я постарался сделать это легко понятным.
Я использую делегатов для общения с потоками.
Например, у меня может быть приложение форм выигрыша, которое загружает файл. Приложение запускает рабочий поток для загрузки (что предотвращает блокировку графического интерфейса). Рабочий поток использует делегатов для отправки сообщений о состоянии (например, о ходе загрузки) обратно в основную программу, чтобы графический интерфейс мог обновлять строку состояния.
Для обработчика событий
Передать метод в параметрах метода
События, другие любые операции
Каждый раз, когда вы хотите инкапсулировать поведение, но вызывать его единообразно. Обработчики событий, функции обратного вызова и т. Д. Вы можете выполнять аналогичные действия, используя интерфейсы и приведение типов, но иногда поведение не обязательно привязано к типу или объекту . Иногда нужно просто инкапсулировать поведение.
Ленивая инициализация параметров! Помимо всех предыдущих ответов (шаблон стратегии, шаблон наблюдателя и т. Д.), Делегаты позволяют вам обрабатывать ленивую инициализацию параметров. Например, предположим, что у вас есть функция Download (), которая занимает довольно много времени и возвращает определенный DownloadedObject. Этот объект используется Хранилищем в зависимости от определенных условий. Обычно вы бы:
storage.Store(conditions, Download(item))
Однако с делегатами (точнее, лямбдами) вы можете сделать следующее, изменив подпись хранилища так, чтобы оно получало Condition и Func <Item, DownloadedObject> и использовать его следующим образом:
storage.Store(conditions, (item) => Download(item))
Следовательно, хранилище будет оценивать делегата только в случае необходимости, выполняя загрузку в зависимости от условий.
Использование делегатов
Параметр сравнения в In Array.Sort (массив T [], сравнение сравнения), List.Sort (сравнение сравнения) и т. Д.
Насколько мне известно, делегаты можно преобразовать в указатели на функции. Это НАМНОГО облегчает жизнь при взаимодействии с машинным кодом, который принимает указатели на функции, поскольку они могут эффективно быть объектно-ориентированными, даже если исходный программист не предусмотрел для этого никаких условий.
Делегаты используются для вызова метода по ссылке. Например:
delegate void del_(int no1,int no2);
class Math
{
public static void add(int x,int y)
{
Console.WriteLine(x+y);
}
public static void sub(int x,int y)
{
Console.WriteLine(x-y);
}
}
class Program
{
static void Main(string[] args)
{
del_ d1 = new del_(Math.add);
d1(10, 20);
del_ d2 = new del_(Math.sub);
d2(20, 10);
Console.ReadKey();
}
}