Почему попытка понять делегатов похожа на попытку понять природу Вселенной?


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

7   51   2010-04-21 01:07:04

7 ответов:

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

вы передаете делегированную функцию для выполнения обратного вызова. Например, при выполнении асинхронного ввода-вывода вы передаете делегированную функцию (функцию, которую вы написали с параметром делегата), которая будет вызвана, когда данные будут считаны с диска.

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

Bullet
    DamageBullet
    HealBullet
    PoisonBullet
    DoSomethingElseBullet
    PoisonAndThenHealBullet
    FooAndBarBullet
    ....

С этой картиной, я должен определите новый подкласс каждый раз, когда я хочу какое-то новое поведение в пуле, которое является беспорядком и приводит к большому количеству дублированного кода. Вместо этого я решил его с делегатами. Пуля имеет делегат OnHit, который вызывается, когда пуля попадает в объект, и, конечно, я могу сделать этот делегат все, что мне нравится. Так что теперь я могу создавать пули, как это

new Bullet(DamageDelegate)

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

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

эта статья от Криса Селлса может помочь:

делегаты .NET: A C# Bedtime Story

делегат-это простой контейнер, который знает, где в памяти машины находится определенный метод.

все делегаты имеют Invoke(...) метод, таким образом, когда у кого-то есть делегат, он может фактически выполнить его, не зная и не беспокоясь о том, что на самом деле делает этот метод.

Это особенно полезно для разделения материалов. GUI-фреймворки были бы невозможны без этой концепции, потому что a Button просто не могу ничего знать о вашей программе вы собираетесь использовать его, поэтому он не может вызывать ваши методы сам по себе, когда он нажат. Вместо этого вы должны указать ему, какие методы он должен вызывать при нажатии.

Я думаю, вы знакомы с событиями, и вы используете их регулярно. Ан event поле-это фактически список таких делегатов (также называемый делегатом с несколькими приведениями). Возможно, все станет яснее, когда мы посмотрим, как мы могли бы "имитировать" события в C#, если бы у него не было event ключевое слово, но только (не мультикаст) делегаты:

public class Button : Rectangle
{
    private List<Delegate> _delegatesToNotifyForClick = new List<Delegate>();

    public void PleaseNotifyMeWhenClicked(Delegate d)
    {
        this._delegatesToNotifyForClick.Add(d);
    }

    // ...

    protected void GuiEngineToldMeSomeoneClickedMouseButtonInsideOfMyRectangle()
    {
        foreach (Delegate d in this._delegatesToNotifyForClick)
        {
            d.Invoke(this, this._someArgument);
        }
    }
}

// Then use that button in your form

public class MyForm : Form
{
    public MyForm()
    {
        Button myButton = new Button();
        myButton.PleaseNotifyMeWhenClicked(new Delegate(this.ShowMessage));
    }

    private void ShowMessage()
    {
        MessageBox.Show("I know that the button was clicked! :))))");
    }
 }

надеюсь, что я мог бы немного помочь. ; -)

может быть, это помогает:

  • делегат-это тип (определяющий сигнатуру метода)
  • экземпляр делегата-это ссылка на метод (он же указатель на функцию)
  • обратный вызов-это параметр типа делегата
  • событие является (своего рода) свойством типа делегата

цель делегатов заключается в том, что вы можете иметь переменные/поля/параметры/свойства(события), которые "держать" функция. Это позволяет хранить / передавать конкретная функция вы выбираете время выполнения. Без него каждый вызов функции должен быть исправлен во время компиляции.

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

  1. простой указатель на функции, как в C / C++ не будет типобезопасным, в .NET компилятор фактически генерирует класс вокруг него, а затем пытается скрыть это как можно больше.

  2. делегаты являются краеугольным камнем LINQ, и есть крутая эволюция от specify-everything в C#1 через анонимные методы (C#2) до lambdas (C#3).

просто познакомьтесь с 1 или 2 стандартными шаблонами.

ребята! Все вы успешно усложнили делегатов:)!

Я постараюсь оставить здесь подсказку: я понял делегатов, как только понял, что jQuery ajax вызывает Javascript. например: "Аякс".send (url, data, successcallback, failcallback) - это сигнатура функции. как вы знаете, он отправляет данные на URL-адрес сервера, в качестве ответа, это может быть 200OK или какая-то другая ошибка. В случае любого такого события(success/fail), вы хотите выполнить функцию. Итак, это действует как прототип функции, чтобы иметь возможность упомянуть в любом успехе или неудаче. Заполнитель может быть не очень универсальный - он может принимать набор параметров и может/не может возвращать значение. Это объявление такого заполнителя, если оно сделано в C#, называется делегатом! Поскольку функции javascript не являются строгими с количеством аргументов, вы просто увидите их как общие заполнители...но C# имеет некоторые строгие объявления... это сводится к делегированию деклараций!!

надеюсь, что это помогает!

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

пример: как использовать

class program {
 public static void Main) {
  List<Employee> empList = new List<Employee> () {
   new Employee () {Name = "Test1", Experience = 6 },
   new Employee () {Name = "Test2", Experience = 2 },
  }

// delegate point to the actual function
IsPromotable isEligibleToPromote = new IsPromotable(IsEligibleToPromoteEmployee)
Employee emp = new Employee();

// pass the delegate to a method where the delegate will be invoked.
emp.PromoteEmployee(empList, isEligibleToPromote);

// same can be achieved using lambda empression no need to declare delegate 
emp.PromoteEmployee (empList, emply =>emply.Experience > 2);

   // this condition can change at calling end 
   public static bool IsEligibleToPromoteEmployee (emp){
      if (emp.Experience > 5)
       return true;
      else
      return false;
    }
  }
}


public delegate bool IsPromotable(Employee emp);

public class Employee  {
  public string Name {get; set;}
  public int Experience {get; set;}

  // conditions changes it can 5, 6 years to promote
  public void PromoteEmployee (List<Employee> employees, IsPromotable isEligibleToPromote) {
  foreach (var employee in employees) {
    // invoke actual function
    if (isEligibleToPromote(employee)){
       Console.WriteLine("Promoted");   
    }
  }
}