Використання делегатів C # в реальному світі [закрито]


16

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


2
Практично кожен клас в рамках .NET-програми демонструє певний набір подій, тому ви йдете. Це просто спосіб інкапсулювати якусь одиницю роботи. Наприклад, скажіть, що ви реалізували загальну структуру бінарних дерев у C. Ну, єдиним способом замовити дерево було б взяти за параметр вказівник функції, який знав, як робити сортування.
Ред С.

Відповіді:


16

Код GUI використовує делегатів для обробки подій, таких як натискання кнопки, переміщення вікон. Використання делегата дозволяє вам мати функцію, яка викликається щоразу, коли відбувається подія. Прикладом може бути посилання функції, яка зберігає дані до кнопки "Зберегти" в інтерфейсі. Після натискання кнопки вона встановлюється для виконання функції, що зберігає дані. Це корисно в програмуванні GUI, оскільки вся ваша програма може чекати, коли користувач щось зробить, і ви не можете знати, що вони зроблять спочатку. Використання делегатів дозволяє підключити функціональні можливості вашої програми до інтерфейсу користувача таким чином, щоб користувач міг робити всі необхідні способи.


2
++ Ти маєш рацію, але я все одно ненавиджу це :-) тому віки тому я придумав це замість цього .
Майк Данлаве

12

Linq використовує параметри Func<T>та Action<T>делегує всюди місце як параметри.

Вони дозволяють використовувати лямбда-вирази як параметри та визначати дію, яку слід здійснити як частину списку параметрів.


12

Практично все, що використовує шаблон спостерігача , можливо, реалізує делегатів.

Прочитайте опис, і ви, мабуть, уявите деякі сценарії, де ви б їх використовували. Загальний приклад обробки подій GUI.


+1, шаблон стратегії - це дійсно де світяться делегати, тобто у вас є клас, де якийсь метод щось робить, але ви хочете, щоб щось було взаємозамінним і без прямої залежності - делегати ergo. Зауважте, що події начебто заповнюють ту саму потребу, що й делегати, різниця полягає в тому, що ви використовуєте делегатів, коли вам потрібно реагувати на якесь повернене значення, тоді як ви просто запускаєте події і все, що буде.
Хомде

9

Делегати є надзвичайно корисними в асинхронному програмуванні.

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


9

Делегати особливо корисні як рішення для отвору середнього шаблону . По суті, існує маса випадків, коли ви хочете зафіксувати унікальний набір інструкцій у загальній купі інструкцій. Особливо складно, якщо інструкціям до та після унікального біта потрібно поділитися станом. З делегатами ви можете просто передати делегата у функції. Функція виконує раніше біт, виконує делегат, а потім виконує після біт.


5

У "старі часи" таких мов, що не є OOP, як Fortran і C, було надзвичайно корисно мати можливість підпрограми отримувати аргумент, який був вказівником на функцію. Наприклад, qsortфункція працює з наданою користувачем функцією порівняння. Існує чимало підпрограм для вирішення звичайних диференціальних рівнянь або для оптимізації функцій, і всі вони приймають покажчики функцій як аргументи.

У віконних системах усі види зворотних викликів дотримуються тієї ж схеми.

У Ліспі навіть у перші дні існувало щось, що називалося "функціональним аргументом" або FUNARG, що було не лише функцією, але й містило контекст зберігання, де він міг запам'ятати та взаємодіяти з частиною зовнішнього світу.

Ця ж потреба існує в мовах OOP, за винятком випадків, коли ви передаєте адресу функції, ви також повинні передавати адресу об'єкта, функцією якого є метод. Це дві речі, які ти повинен пройти. Тож саме делегат - це саме те, що дозволяє використовувати цей старий добрий зразок.


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

2

Першою моєю зустріччю з делегатами була перевірка оновлення програми (Windows форми C # 3.5), завантаження файлу з мого веб-сайту, але, щоб уникнути перевірки оновлення, блокуючи всю програму, я використовував делегата та нитку, щоб зробити це асинхронно.


1

Я бачив цікаві реалізації стратегії, яка ефективно використовує делегатів. (тобто стратегія є делегатом)

Я дивився на те, щоб знайти маршрутизацію, де алгоритм пошуку шляху був делегатом, який може бути (повторно) призначений під час виконання, щоб можна було використовувати різні алгоритми (BFS vs A * тощо)


1

Багато класичних шаблонів GoF можуть бути реалізовані з делегатами: Наприклад, шаблон команди, шаблон відвідувача, шаблон стратегії, заводський візерунок та шаблон спостерігача часто можуть бути реалізовані за допомогою простого делегата. Іноді клас краще (наприклад, коли команді потрібно ім'я або об'єкт стратегії потрібно серіалізувати), але в більшості випадків використовувати Action<...>або Func<...>набагато елегантніше, ніж створювати виділений однометодний інтерфейс.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.