Когда бы вы использовали делегаты в C #?

Как вы используете делегаты в C #?


person Maxime Rouiller    schedule 10.10.2008    source источник
comment
Вы имеете в виду делегатов в системе типов .NET или синтаксис делегатов C #? Вы имеете в виду, когда вы используете синтаксис делегата вместо синтаксиса лямбда-выражения или вы имеете в виду, когда вы используете делегаты вместо классов / интерфейсов / виртуальных методов / и т. Д.?   -  person Niki    schedule 01.08.2009
comment


Ответы (20)


Теперь, когда у нас есть лямбда-выражения и анонимные методы в C #, я гораздо чаще использую делегаты. В C # 1, где всегда приходилось иметь отдельный метод для реализации логики, использование делегата часто не имело смысла. В наши дни я использую делегатов для:

  • Обработчики событий (для графического интерфейса и др.)
  • Начальные темы
  • Обратные вызовы (например, для асинхронных API)
  • LINQ и аналогичные (List.Find и т. Д.)
  • В любом другом месте, где я хочу эффективно применить "шаблонный" код с некоторой специализированной логикой внутри (где делегат предоставляет специализацию)
person Jon Skeet    schedule 10.10.2008
comment
Стоит упомянуть push в Push LINQ? - person Marc Gravell; 10.10.2008
comment
Не уверен, как бы я объяснил это вкратце, не усложняя ситуацию :) (Возможно, это покрыто обработчиками событий, LINQ и битом templaty в любом случае! - person Jon Skeet; 10.10.2008
comment
Ваше первое предложение не имеет особого смысла. - person senfo; 19.02.2009
comment
@senfo: Теперь в этом больше смысла? - person Jon Skeet; 19.02.2009
comment
Я знаю, что вы пытаетесь сказать, но мне было бы легче читать следующее: Теперь, когда у нас есть лямбда-выражения и анонимные методы в C #, я гораздо чаще использую делегаты. Я знаю, что придираюсь к мелочам, но мне действительно пришлось прочитать это предложение несколько раз, прежде чем оно стало для меня осмысленным. - person senfo; 19.02.2009
comment
+1 за смелость бросить вызов достопочтенному мистеру Скиту ;-) - person indra; 24.11.2010
comment
Хотел бы я увидеть пример кода - person RollRoll; 20.03.2013

Делегаты очень полезны для многих целей.

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

Вот глупый пример - я уверен, что вы можете экстраполировать из этого что-нибудь более полезное:

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");
    }
}
person Andrew Hare    schedule 31.07.2009
comment
Метод static Boolean inMyFamily(String name) является делегатом. Где принимает делегата в качестве параметра. Поскольку делегаты являются просто указателями на функции, когда вы передаете имя метода в .Where(delegate), который становится делегатом. Поскольку inMyFamily возвращает логический тип, он фактически считается предикатом. Предикаты - это просто делегаты, возвращающие логические значения. - person Landon Poch; 22.08.2012
comment
Предикаты - это просто делегаты, возвращающие логические значения. +1 - person daehaai; 06.02.2013
comment
@LandonPoch, этот комментарий лучше было бы поместить в ответ. я, будучи новичком, не мог понять, где это. благодаря. - person Eakan Gopalakrishnan; 04.09.2014
comment
@Eakan, на самом деле я не отвечал на главный вопрос (когда вы использовали бы делегатов), поэтому я оставил его как комментарий. - person Landon Poch; 04.09.2014

Нашел еще один интересный ответ:

Сотрудник только что задал мне этот вопрос - в чем смысл делегатов в .NET? Мой ответ был очень коротким, и он не нашел его в сети: отложить выполнение метода.

Источник: LosTechies

Так же, как это делает LINQ.

person Maxime Rouiller    schedule 16.10.2008
comment
+1 .. не думал об этом так. Хорошая точка зрения - person Luke101; 19.05.2012

Вы можете использовать делегаты для объявления переменных и параметров с функциональным типом.

Пример

Рассмотрим модель «заимствования ресурсов». Вы хотите контролировать создание и очистку ресурса, позволяя клиентскому коду «заимствовать» ресурс между ними.

Это объявляет тип делегата.

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] );
    } );
person harpo    schedule 10.10.2008

Делегаты часто могут использоваться вместо интерфейса с одним методом, типичным примером этого может быть шаблон наблюдателя. На других языках, если вы хотите получать уведомление о том, что что-то произошло, вы можете определить что-то вроде:

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);

Надеюсь, это поможет!

person jonnii    schedule 31.07.2009
comment
Хорошие примеры с синтаксисом .. Спасибо .. :) - person Raghu; 30.11.2011

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

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);
    }
}
person will    schedule 05.10.2012

Немного другое использование - ускорение отражения; т.е. вместо использования отражения каждый раз вы можете использовать Delegate.CreateDelegate для создания (типизированного) делегата метода (MethodInfo) и вместо этого вызывать этот делегат. Тогда это будет намного быстрее на вызов, поскольку проверки уже были выполнены.

С Expression вы также можете сделать то же самое для создания кода на лету - например, вы можете легко создать Expression, который представляет оператор + для типа, выбранного во время выполнения (чтобы обеспечить поддержку операторов для универсальных шаблонов, чего язык не предоставлять); и вы можете скомпилировать Expression в типизированный делегат - работа сделана.

person Marc Gravell    schedule 10.10.2008

Делегаты используются каждый раз, когда вы используете события - это механизм, по которому они работают.

Кроме того, делегаты очень полезны для таких вещей, как использование запросов LINQ. Например, многие запросы LINQ принимают делегат (часто Func<T,TResult>), который можно использовать для фильтрации.

person Reed Copsey    schedule 31.07.2009

подписка обработчиков событий на события

person Manu    schedule 10.10.2008

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

person rookie1024    schedule 10.10.2012

Я использую делегатов для общения с потоками.

Например, у меня может быть приложение форм выигрыша, которое загружает файл. Приложение запускает рабочий поток для загрузки (что предотвращает блокировку графического интерфейса). Рабочий поток использует делегатов для отправки сообщений о состоянии (например, о ходе загрузки) обратно в основную программу, чтобы графический интерфейс мог обновлять строку состояния.

person Danny Frencham    schedule 21.10.2008

  1. Для обработчика событий

  2. Передать метод в параметрах метода

person Patrick Desjardins    schedule 10.10.2008

Первая линия использования - замена паттерна Наблюдатель / Наблюдаемый (события). Вторая, красивая элегантная версия паттерна Стратегия. Можно собрать множество других употреблений, хотя я думаю, более эзотерических, чем эти первые два.

person x0n    schedule 10.10.2008

События, другие любые операции

person Community    schedule 10.10.2008

Каждый раз, когда вы хотите инкапсулировать поведение, но вызывать его единообразно. Обработчики событий, функции обратного вызова и т. Д. Подобные вещи можно выполнять с помощью интерфейсов и приведения типов, но иногда поведение не обязательно привязано к типу или объекту. Иногда нужно просто инкапсулировать поведение.

person Bob King    schedule 10.10.2008

Ленивая инициализация параметров! Помимо всех предыдущих ответов (шаблон стратегии, шаблон наблюдателя и т. Д.), Делегаты позволяют обрабатывать ленивую инициализацию параметров. Например, предположим, что у вас есть функция Download (), которая занимает довольно много времени и возвращает определенный DownloadedObject. Этот объект используется Хранилищем в зависимости от определенных условий. Обычно вы бы:

storage.Store(conditions, Download(item))

Однако с делегатами (точнее, лямбдами) вы можете сделать следующее, изменив подпись хранилища так, чтобы оно получило Condition и Func ‹Item, DownloadedObject› и использовать его следующим образом:

storage.Store(conditions, (item) => Download(item))

Следовательно, хранилище будет оценивать делегата только при необходимости, выполняя загрузку в зависимости от условий.

person Santiago Palladino    schedule 10.10.2008
comment
Незначительный момент, но точнее, лямбды - вы могли бы сделать то же самое с анонимным методом в C # 2.0, хотя он был бы более подробным: delegate (ItemType item) {[return] Download (item);} - person Marc Gravell; 10.10.2008
comment
Конечно, как и LINQ: лямбда-выражения - это не более чем синтаксический сахар для делегатов. Они просто сделали делегатов более доступными. - person Santiago Palladino; 10.10.2008
comment
Лямбды - это немного больше, чем просто делегаты, поскольку они могут быть преобразованы в деревья выражений, а также в делегаты. - person Jon Skeet; 10.10.2008
comment
Ну, лямбда-выражения также могут быть скомпилированы в выражения, которые полностью отличаются от делегатов. Но в вашем примере используются Func ‹,›, которые можно использовать из анон-метода. Выражения на C # 2.0 было бы крайне болезненно писать. - person Marc Gravell; 10.10.2008

Использование делегатов

  1. Обработка событий
  2. Мульти-кастинг
person Rajeshwaran S P    schedule 10.10.2008

Параметр сравнения в In Array.Sort (массив T [], сравнение сравнения), List.Sort (сравнение сравнения) и т. Д.

person GregUzelac    schedule 11.10.2008

Насколько мне известно, делегаты можно преобразовать в указатели на функции. Это НАМНОГО упрощает жизнь при взаимодействии с машинным кодом, который принимает указатели на функции, поскольку они могут эффективно быть объектно-ориентированными, даже если исходный программист не предусмотрел для этого никаких условий.

person Puppy    schedule 25.08.2010

Делегаты используются для вызова метода по ссылке. Например:

  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();
        }
    }
person mahesh    schedule 07.02.2012