Делегаты, почему? [duplicate]

Возможные дубликаты:
Когда вы будете использовать делегатов в C #?
Назначение делегатов

Я видел много вопросов относительно использования делегаты. Мне до сих пор не ясно, где и ПОЧЕМУ вы бы использовали делегаты вместо непосредственного вызова метода.

Я слышал эту фразу много раз: «Затем объект делегата может быть передан в код, который может вызывать ссылочный метод, почему бы просто не вызвать этот метод напрямую? Мне кажется, что мне нужно написать больше кода для использования делегатов, чем просто для непосредственного использования функций.

Может кто-нибудь подсказать мне ситуацию в реальном мире? Я в полном замешательстве.

55
задан Community 23 May 2017 в 02:02
поделиться

12 ответов

В качестве конкретного примера, я недавно использовал делегат SendAsync () на System.Net.Mail.SmtpClient . У меня есть приложение, которое отправляет тонны и тонны электронной почты, и было заметное снижение производительности в ожидании, когда сервер Exchange примет сообщение. Однако необходимо было регистрировать результат взаимодействия с этим сервером.

Поэтому я написал метод делегата для обработки этого журнала и передал его в SendAsync () (раньше мы просто использовали Send () ) при отправке каждого электронного письма. Таким образом, он может перезвонить делегату, чтобы записать результат, и потоки приложения не дожидаются завершения взаимодействия, прежде чем продолжить.

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

2
ответ дан 7 November 2019 в 07:24
поделиться
18
ответ дан 7 November 2019 в 07:24
поделиться

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

private int DoSomeOperation( Operations operation )
{
    return operation.Invoke(5,5);
}

...

MyClass f = new MyClass();
Operations p = new Operations(f.multiply);
int result = DoSomeOperation( p );

Делегаты превращают методы в вещи, которые можно передавать так же, как int. Вы могли бы сказать, что переменные не дают вам ничего лишнего, потому что в

int i = 5;
Console.Write( i + 10 );

вы видите указанное значение 5, так что вы можете просто сказать Console.Write (5 + 10) . В этом случае это правда, но он упускает преимущества возможности сказать

DateTime nextWeek = DateTime.Now.AddDays(7);

вместо того, чтобы определять специальный метод DateTime.AddSevenDays () и метод AddSixDays , и так далее.

2
ответ дан 7 November 2019 в 07:24
поделиться

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

public delegate void UpdateTextBox(string data);

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    ...
    Invoke(new UpdateTextBox(textBoxData), data);
    ...

}

private void textBoxData(string data)
{
            textBox1.Text += data;
}
2
ответ дан 7 November 2019 в 07:24
поделиться

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

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

1
ответ дан 7 November 2019 в 07:24
поделиться
1
ответ дан 7 November 2019 в 07:24
поделиться

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

Объект goo имеет доступ как к foo, так и к bar, поэтому он может связать их вместе с помощью делегатов. Обычно бар и слизь часто являются одним и тем же объектом.

Например, класс Button обычно не имеет никакого доступа к классу, определяющему метод Button_click.

Итак, теперь, когда у нас есть это, мы можем использовать его для множества других вещей, помимо событий. Асинхронные шаблоны и Linq — два примера.

1
ответ дан 7 November 2019 в 07:24
поделиться

Делегаты чрезвычайно полезны, особенно после введения linq и замыканий.

Хорошим примером является функция «Где», один из стандартных методов linq. «Где» принимает список и фильтр и возвращает список элементов, соответствующих фильтру. (Аргумент filter — это делегат, который принимает T и возвращает логическое значение.)

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

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

var result = list.Where(x => x != null);
...

вместо этого:

var result = new List<T>();
foreach (var e in list)
    if (e != null)
        result.add(e)
...
11
ответ дан 7 November 2019 в 07:24
поделиться

Делегаты не могут изменять функциональность во время выполнения.

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

Например:

class Person
{
    public string Name { get; }
    public int Age { get; }
    public double Height { get; }
    public double Weight { get; }
}

IEnumerable<Person> people = GetPeople();

var orderedByName = people.OrderBy(p => p.Name);
var orderedByAge = people.OrderBy(p => p.Age);
var orderedByHeight = people.OrderBy(p => p.Height);
var orderedByWeight = people.OrderBy(p => p.Weight);

В приведенном выше коде p => p.Name, p => p.Age и т. д. — все лямбда-выражения, которые оцениваются как Func делегатов (где Tstring, int, double и double соответственно).

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

public static IEnumerable<Person> OrderByName(this IEnumerable<Person> people);
public static IEnumerable<Person> OrderByAge(this IEnumerable<Person> people);
public static IEnumerable<Person> OrderByHeight(this IEnumerable<Person> people);
public static IEnumerable<Person> OrderByWeight(this IEnumerable<Person> people);

Это было бы полным отстой. Я имею в виду, во-первых, код стал бесконечно менее пригодным для повторного использования, поскольку он применяется только к коллекциям типа Person. Кроме того, нам нужно скопировать и вставить один и тот же код четыре раза, изменяя только 1 или 2 строки в каждой копии (где есть ссылка на соответствующее свойство Person — иначе все выглядело бы одинаково)! Это быстро превратилось бы в неуправляемый беспорядок.

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

28
ответ дан 7 November 2019 в 07:24
поделиться

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

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

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

public delegate void SimpleAction();

public class Timer {
    public Timer(int secondsBetweenActions, SimpleAction simpleAction) {}
}

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

9
ответ дан 7 November 2019 в 07:24
поделиться

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

Ниже приведен мой пример того, как делегаты позволяют классу-потребителю изменять или дополнять поведение (путем эффективного добавления «крючков», чтобы потребитель мог делать что-то до или после критического действия и/или полностью предотвращать такое поведение). Обратите внимание, что вся логика принятия решений предоставляется извне класса StringSaver. Теперь учтите, что может быть 4 разных потребителя этого класса — каждый из них может реализовать свою собственную Verification и Логика уведомления или никакая, в зависимости от обстоятельств.

internal class StringSaver
{
    public void Save()
    {
        if(BeforeSave != null)
        {
            var shouldProceed = BeforeSave(thingsToSave);
            if(!shouldProceed) return;
        }
        BeforeSave(thingsToSave);

        // do the save

        if (AfterSave != null) AfterSave();
    }

    IList<string> thingsToSave;
    public void Add(string thing) { thingsToSave.Add(thing); }

    public Verification BeforeSave;
    public Notification AfterSave;
}

public delegate bool Verification(IEnumerable<string> thingsBeingSaved);
public delegate void Notification();

public class SomeUtility
{
    public void SaveSomeStrings(params string[] strings)
    {
        var saver = new StringSaver
            {
                BeforeSave = ValidateStrings, 
                AfterSave = ReportSuccess
            };

        foreach (var s in strings) saver.Add(s);

        saver.Save();
    }

    bool ValidateStrings(IEnumerable<string> strings)
    {
        return !strings.Any(s => s.Contains("RESTRICTED"));
    }

    void ReportSuccess()
    {
        Console.WriteLine("Saved successfully");
    }
}

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

1
ответ дан 7 November 2019 в 07:24
поделиться

Приведу пример. Если ваш класс предоставляет событие, ему может быть назначено некоторое количество делегатов во время выполнения, которые будут вызываться, чтобы сигнализировать о том, что что-то произошло. Когда вы писали класс, вы понятия не имели, какие делегаты он будет запускать. Вместо этого это определяется тем, кто использует ваш класс.

7
ответ дан 7 November 2019 в 07:24
поделиться
Другие вопросы по тегам:

Похожие вопросы: