Реальное использование C # Делегатов [закрыто]

16

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

AlexC
источник
2
Почти каждый отдельный класс в .NET Framework предоставляет некоторый набор событий, так что все готово. Это просто способ инкапсулировать какую-то единицу работы. Например, допустим, что вы реализовали общую двоичную древовидную структуру на языке C. Ну, единственный способ упорядочить ваше дерево - это взять в качестве параметра указатель на функцию, которая знает, как выполнить сортировку.
Эд С.

Ответы:

16

Код GUI использует делегаты для обработки событий, таких как нажатие кнопок, перемещение окон. Использование делегата позволяет вам вызывать функцию всякий раз, когда происходит событие. Примером может служить связывание функции, которая сохраняет данные, с кнопкой «Сохранить» в интерфейсе. Когда кнопка нажата, она настроена на выполнение функции сохранения данных. Это полезно в программировании GUI, потому что вся ваша программа может ждать, пока пользователь что-то сделает, и у вас нет возможности узнать, что они будут делать в первую очередь. Использование делегатов позволяет подключать функциональные возможности вашей программы к пользовательскому интерфейсу таким образом, чтобы пользователь мог делать что-либо по своему усмотрению.

FrustratedWithFormsDesigner
источник
2
++ Вы правы, но я все еще ненавижу это :-), так что давным-давно я придумал это вместо этого .
Майк Данлавей
12

Linq использует Func<T>и Action<T>делегирует повсеместно в качестве параметров.

Это позволяет вам использовать лямбда-выражения в качестве параметров и определять действие, которое необходимо выполнить как часть списка параметров.

Одед
источник
12

Практически все, что использует шаблон наблюдателя , вероятно, будет реализовывать делегатов.

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

как зовут
источник
+1, паттерн стратегии действительно там, где сияют делегаты, т. Е. У вас есть некоторый класс, где какой-то метод что-то делает, но вы хотите, чтобы что-то было взаимозаменяемо и без прямой зависимости, то есть делегаты. Обратите внимание, что события как бы удовлетворяют ту же потребность, что и делегаты, разница в том, что вы используете делегатов, когда вам нужно реагировать на какое-то возвращаемое значение, тогда как вы просто запускаете события и все, что будет.
Homde
9

Делегаты чертовски полезны в асинхронном программировании.

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

Джеймс Лав
источник
9

Делегаты особенно полезны в качестве решения для отверстия в средней схеме . По сути, во многих случаях вы хотите заключить уникальный набор инструкций в общий набор инструкций. Это особенно сложно, если инструкции до и после уникального бита должны совместно использовать состояние. С делегатами вы можете просто передать делегат в функцию. Функция выполняет бит before, выполняет делегат, затем выполняет бит after.

Скотт Уитлок
источник
5

В «старые времена» не-ООП-языков, таких как Fortran и C, было невероятно полезно иметь подпрограмму, получающую аргумент, который был указателем на функцию. Например, qsortфункция работает с предоставленной пользователем функцией сравнения. Существует множество подпрограмм для решения обыкновенных дифференциальных уравнений или для оптимизации функций, и все они принимают указатели на функции в качестве аргументов.

В оконных системах все виды обратных вызовов следуют одному и тому же шаблону.

В Лиспе, даже в первые дни, было нечто, называемое «функциональный аргумент» или FUNARG, который был не только функцией, но также содержал контекст хранения, где он мог помнить и взаимодействовать с частью внешнего мира.

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

Майк Данлавей
источник
3

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

Action<Button, Action<Button>> prepareButton = 
    (btn, nxt) => { 
        btn.Height = 32;
        btn.Width= 64;
        nxt(btn);
    };

prepareButton(myBtn1, btn => btn.Text = "A");
prepareButton(myBtn2, btn => btn.Text = "B");
prepareButton(myBtn3, btn => btn.Text = "C");

Вот реальный пример того преимущества, которое предоставляют делегаты.

protected override void PageInitialize()
{
    const string selectCodeFormat = "javascript:selectCode('{0}', '{1}');";
    const string onClick = "return toggleElement(this);";

    Func<HtmlGenericControl> getElement = null;
    Action<HtmlGenericControl> setElement = null, addChild = null;
    HtmlGenericControl level1Element = null, level2Element = null, level3Element = null, level4Element = null;
    string className = null, code = null, description = null;           

    using (var records = Core.Database.ExecuteRecords("code.SocCodeTree"))
    {
        while (records.Read())
        {
            code = records.GetString("Code");
            description = records.GetString("Description"); 

            if (records.GetString("Level4") != "")
            {
                className = "Level4";
                setElement = e => level4Element = e;
                getElement = () => level4Element;
                addChild = e => level3Element.Controls.Add(e);
            }
            else if (records.GetString("Level3") != "")
            {
                className = "Level3";
                setElement = e => level3Element = e;
                getElement = () => level3Element;
                addChild = e => level2Element.Controls.Add(e);
            }
            else if (records.GetString("Level2") != "")
            {
                className = "Level2";
                setElement = e => level2Element = e;
                getElement = () => level2Element;
                addChild = e => level1Element.Controls.Add(e);
            }
            else
            {
                className = "Level1";
                setElement = e => level1Element = e;
                getElement = () => level1Element;
                addChild = e => Root.Controls.Add(e);
            }

            var child = new HtmlGenericControl("li");
            child.Attributes["class"] = className;
            var span = new HtmlGenericControl("span") { 
                InnerText = code + " - " + description + " - " 
            };
            span.Attributes["onclick"] = onClick;
            child.Controls.Add(span);
            var a = new HtmlAnchor() { 
                InnerText = "Select", 
                HRef = string.Format(selectCodeFormat, code, description) 
            };
            child.Controls.Add(a);
            setElement(new HtmlGenericControl("ul"));
            child.Controls.Add(getElement());
            addChild(child);    
        }
    }
}
ChaosPandion
источник
2

Моя первая встреча с делегатами заключалась в проверке обновления программы (Windows Form C # 3.5) путем загрузки файла с моего веб-сайта, но чтобы избежать проверки обновления, блокирующей всю программу, я использовал делегат и поток, чтобы сделать это асинхронно.

кругозор
источник
1

Я видел интересные реализации шаблона стратегии, который эффективно использует делегатов. (т.е. стратегия является делегатом)

Тот, на который я смотрел, был для поиска пути, где алгоритм для поиска пути был делегатом, который мог быть (пере) назначен во время выполнения так, чтобы могли использоваться различные алгоритмы (BFS против A * и т. Д.)

Стивен Эверс
источник
1

Многие классические шаблоны GoF могут быть реализованы с помощью делегатов: например, шаблон Command, шаблон Visitor, шаблон Strategy, шаблон Factory и шаблон Observer часто могут быть реализованы с помощью простого делегата. Иногда класс лучше (например, когда команде нужно имя или стратегический объект должен быть сериализован), но в большинстве случаев использование Action<...>или Func<...>гораздо более элегантно, чем создание выделенного интерфейса с одним методом.

nikie
источник