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

StackOverflow https://stackoverflow.com/questions/2541683

  •  23-09-2019
  •  | 
  •  

Вопрос

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

Это было полезно?

Решение

Проще говоря, это по сути указатель на метод.

У вас может быть переменная, содержащая тип делегата (точно так же, как у вас есть переменная int, которая может содержать тип int).Вы можете выполнить метод, на который указывает делегат, просто вызвав переменную как функцию.

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

Это очень удобно, когда вы хотите, чтобы объект выполнял действия на основе заданных пользователем критериев.Например, фильтрация списка на основе определяемого пользователем выражения true/false.Вы можете позволить пользователю указать функцию делегата, которая будет использоваться в качестве фильтра для оценки каждого элемента списка.

Другие советы

У меня есть функция:

public long GiveMeTwoTimesTwo()
{
    return 2 * 2;
}

Эта функция отстой.А что, если я хочу 3*3?

public long GiveMeThreeTimesThree()
{
    return 3 * 3;
}

Слишком много текста.Мне лень!

public long SquareOf(int n)
{
    return n * n;
}

Мой SquareOf функции все равно, что n является.Он будет работать корректно при любом n прошел внутрь.Он не знает точно, какой номер n есть, но это делает знай это n является целым числом.Ты не можешь пройти "Haha not an integer" в SquareOf.

Вот еще одна функция:

public void DoSomethingRad()
{
    int x = 4;
    long y = SquareOf(x);
    Console.WriteLine(y);
}

Вопреки своему названию, DoSomethingRad на самом деле не делает ничего крутого.Однако он записывает SquareOf(4), равный 16.Можем ли мы изменить это, чтобы оно было менее скучным?

public void DoSomethingRad(int numberToSquare)
{
    long y = SquareOf(numberToSquare);
    Console.WriteLine(y);
}

DoSomethingRad явно все еще довольно неудачен.Но, по крайней мере, теперь мы можем передать число в квадрат, чтобы он не записывал каждый раз 16.(Он напишет 1, или 4, или 9, или 16, или...зззз все равно скучно).

Было бы неплохо, если бы был способ изменить то, что происходит с переданным числом.Может быть, мы не хотим решать эту проблему;может быть, мы захотим возвести его в куб или вычесть из 69 (число, случайно выбранное в моей голове).

При дальнейшем рассмотрении кажется, что единственная часть SquareOf что DoSomethingRad волнует то, что мы можем дать ему целое число (numberToSquare) и что это дает нам long (потому что мы помещаем возвращаемое значение в y и y это long).

public long CubeOf(int n)
{
    return n * n * n;
}

public void DoSomethingLeet(int numberToSquare)
{
    long y = CubeOf(numberToSquare);
    Console.WriteLine(y);
}

Посмотрите, насколько похожи DoSomethingLeet это DoSomethingRad?Если бы только был способ пройти поведение (DoX()) вместо просто данные (int n)...

Итак, теперь, если мы хотим написать квадрат числа, мы можем DoSomethingRad и если мы хотим записать куб числа, мы можем DoSomethingLeet.Итак, если мы хотим записать число, вычтенное из 69, нужно ли нам создать другой метод, DoSomethingCool?Нет, потому что это требует слишком много набора текста (и, что более важно, это мешает нам изменить интересное поведение, изменив только один аспект нашей программы).

Итак, мы приходим к:

public long Radlicious(int doSomethingToMe, Func<int, long> doSomething)
{
    long y = doSomething(doSomethingToMe);
    Console.WriteLine(y);
}

Мы можем вызвать этот метод, написав следующее:

Radlicious(77, SquareOf);

Func<int, long> это особый вид делегата.Он хранит поведение, которое принимает целые числа и выдает longс.Мы не уверены, что метод, на который он указывает, будет делать с любым переданным нам целым числом;все, что мы знаем, это то, что, что бы ни случилось, мы получим long назад.

Нам не нужно задавать какие-либо параметры SquareOf потому что Func<int, long> описывает поведение, а не данные.Вызов Radlicious(77, SquareOf) просто дает Radlicious общее поведение SquareOf («Я беру число и возвращаю его квадрат»), а не что SquareOf сделаю с любым специфический целое число.

Итак, если вы поняли, о чем я говорю, то вы меня уже превзошли, потому что я сам этого не понимаю.

*КОНЕЦ ОТВЕТ, НАЧИНАЕТСЯ СТРАНСТВУЮЩИЙ ИДИОТИЙ*

Я имею в виду, это похоже на ints может быть воспринято как просто очень скучное поведение:

static int Nine()
{
    return 9;
}

Тем не менее, грань между тем, что является данными и поведением, кажется, стирается, и то, что обычно воспринимается как данные, является просто скучным поведением.

Конечно, можно представить супер «интересное» поведение, которое принимает всевозможные абстрактные параметры, но требует тонны информации для его вызова.Что, если от нас потребуется предоставить исходный код, который он скомпилирует и запустит для нас?

Что ж, тогда наша абстракция, похоже, вернула нас к исходной точке.У нас поведение настолько абстрактное, что требуется весь исходный код нашей программы, чтобы определить, что она собирается делать.Это полностью неопределенное поведение:функция может сделать что-либо, но оно должно быть обеспечено все чтобы определить, что он делает.С другой стороны, полностью детерминированное поведение, такое как Nine(), не требует никакой дополнительной информации, но не может ничего сделать, кроме возврата 9.

Ну и что?Я не знаю.

Делегат — это указатель на метод.Затем вы можете использовать свой делегат в качестве параметра других методов.

здесь это ссылка на простой учебник.

Вопрос, который у меня был, был: «Итак, зачем мне это сделать?» Вы на самом деле не будете «получить», пока не решите проблему программирования с ними.

Интересно, что никто не упомянул одно из ключевых преимуществ делегирования — оно предпочтительнее создания подклассов, когда вы понимаете, что наследование не является волшебным средством и обычно создает больше проблем, чем решает.Это основа многих шаблонов проектирования, особенно стратегия шаблон.

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

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

Он просто ссылается на метод.Они отлично пригодятся при работе с поперечной резьбой.

Вот пример прямо из моего кода.

 //Start our advertisiment thread
    rotator = new Thread(initRotate);
    rotator.Priority = ThreadPriority.Lowest;
    rotator.Start();

    #region Ad Rotation
    private delegate void ad();
    private void initRotate()
    {
        ad ad = new ad(adHelper);
        while (true)
        {
            this.Invoke(ad);
            Thread.Sleep(30000);
        }

    }

    private void adHelper()
    {
        List<string> tmp = Lobby.AdRotator.RotateAd();
        picBanner.ImageLocation = @tmp[0].ToString();
        picBanner.Tag = tmp[1].ToString();            
    }
    #endregion

Если бы вы не использовали делегат, вы не смогли бы выполнить перекрестное соединение и вызвать функцию Lobby.AdRotator.

Как говорили другие, делегат — это ссылка на функцию.Одно из наиболее полезных применений (IMO) — это мероприятия.Когда вы регистрируете событие, вы регистрируете функцию для вызова события, и делегаты идеально подходят для этой задачи.

Проще говоря, делегат — это просто переменная, содержащая функцию (ссылку на нее).Делегаты полезны, потому что они позволяют передавать функцию как переменную, не беспокоясь о том, «откуда» функция на самом деле взялась.

Конечно, важно отметить, что функция не копируется, когда она объединяется в переменную;это просто связано по ссылке.Например:

class Foo
{
    public string Bar
    {
        get;
        set;
    }

    public void Baz()
    {
        Console.WriteLine(Bar);
    }
}

Foo foo = new Foo();
Action someDelegate = foo.Baz;

// Produces "Hello, world".
foo.Bar = "Hello, world";
someDelegate();

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

То же самое и с кодом.Делегат — это тип, это объект, способный выполнить метод.

например.

Class Person
{
   public string GetPersonName(Person person)
   {
     return person.FirstName + person.LastName;
   }

   //Calling the method without the use of delegate
   public void PrintName()
   {
      Console.WriteLine(GetPersonName(this));
   }

   //using delegate
   //Declare delegate which matches the methods signature
   public delegate string personNameDelegate(Person person);

  public void PrintNameUsingDelegate()
  {
      //instantiate
      personNameDelegate = new personNameDelegate(GetPersonName);

      //invoke
      personNameDelegate(this);
  }

}

Метод GetPersonName вызывается с использованием объекта делегата personNameDelegate.В качестве альтернативы мы можем использовать метод PrintNameUsingDelegate, который будет принимать делегат в качестве параметра.

public void PrintNameUsingDelegate(personNameDelegate pnd, Person person)
{
   pnd(person);
}

Преимущество в том, что если кто-то хочет напечатать имя как «фамилия_первое имя», ему/ей просто нужно обернуть этот метод в personNameDelegate и перейти к этой функции.Никакого дальнейшего изменения кода не требуется.

Делегаты особенно важны в

  1. События
  2. Асинхронные вызовы
  3. LINQ (как лямбда-выражения)

Если вы собираетесь делегировать задачу кому-то, делегатом будет тот, кто получает работу.

В программировании это ссылка на блок кода, который действительно знает, как что-то сделать.Часто это указатель на функцию или метод, который будет обрабатывать какой-либо элемент.

В самых простых терминах я могу придумать следующее:Делегат переложит бремя работы в руки класса, который в значительной степени знает, что делать.Думайте об этом как о ребенке, который не хочет вырасти полностью похожим на своего старшего брата, но все еще нуждается в его руководстве и приказах.Вместо того, чтобы наследовать все методы от своего брата (то есть создавать подклассы), он просто заставляет своего брата выполнять работу или Младший брат делает что-то, что требует действий, предпринятых старшим братом.Когда вы попадаете в строки протоколов, старший брат определяет, что абсолютно необходимо, или он может предоставить вам гибкость в выборе того, что вы хотите заставить его делать в определенных событиях (т. е. неформальные и формальные протоколы, как описано в Objective-C).

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top