Подтвердить что ты не робот

В чем разница между делегатом и действием в С#

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

Но то, что я хочу знать, - это их использование в реальном мире. Пожалуйста, не давайте пример Hello World или класс Animal, они слишком базовые.

Например,

  • В чем разница между ними
  • Когда использовать делегат или действие
  • Если не использовать делегат или действие
  • Когда они могут быть более убитыми
4b9b3361

Ответ 1

Action является Delegate. Он определяется следующим образом:

public delegate void Action();

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

class Program
{
    public static void FooMethod()
    {
        Console.WriteLine("Called foo");
    }

    static void Main()
    {
        Action foo = FooMethod; // foo now references FooMethod()
        foo(); // outputs "Called foo"
    }
}

Ответ 2

Когда вы определяете делегат, вы по существу определяете подпись метода (тип и аргументы возврата).

Действие - это делегат, который уже определен (void return и no args).

public delegate void Action()

Вы можете перейти к определению и увидеть его самостоятельно. Или здесь, в документах. http://msdn.microsoft.com/en-us/library/system.action.aspx

Я почти всегда использую существующие общие делегаты (из которых одно действие), когда подпись метода, который я ищу, соответствует поддерживаемым подписям. Хорошая идея об использовании общих делегатов заключается в том, что они хорошо известны. Большинство разработчиков знают, что действие пустое/пустое. Если бы я определил свою собственную версию Action, всем нужно было бы найти ее подписи, и я просто дублировал то, что уже существует.

Примеры... Действие случается немного реже, поскольку цель метода void/void может быть только для мутации. Func очень распространен (также общий делегат). Есть примеры его использования по всей структуре, особенно в linq. Посмотрите, например, где. http://msdn.microsoft.com/en-us/library/bb534803.aspx. Это Func означает, что он принимает элемент типа коллекции, над которой вы работаете как параметр, и возвращает bool. В контексте выражения where, когда Func return true означает включение его в результаты наоборот, для false.

public static IEnumerable<TSource> Where<TSource>(
    this IEnumerable<TSource> source,
    Func<TSource, bool> predicate
)

Ответ 3

Так как Кеннет и Сидж уже указали код и MSDN, я просто попытаюсь заполнить пример реального мира.

Рассмотрим делегат, который определяет "перемещение".

Представителем "Action" в реальном мире будет "Run" или "Walk". Вы не заботитесь о том, какую скорость вы двигаете, какой маршрут вы берете или сообщают о времени, которое требуется для перемещения.

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

public delegate void MoveAction();
public delegate int MoveDelegate(int speed);

Расширение примеров осады.

class Program
{
    public static void Run()
    {
        Console.WriteLine("Running");
    }

    public static int RunAtSpeed(int speed)
    {
         // logic to run @ speed and return time
         Console.WriteLine("Running @ {0}", speed); 
         return 10;
    }

    public static int WalkAtSpeed(int speed)
    {
         // logic to walk @ speed and return time
         Console.WriteLine("Walking @ {0}", speed); 
         return 20;
    }

    static void Main()
    {
        Action foo = Run; 
        foo(); 

        MoveDelegate run = RunAtSpeed;
        int result1 = run(5);

        MoveDelegate walk = WalkAtSpeed;
        int result2 = walk(1);
    }
}

Ответ 4

Что такое действие: Достаточно просто Action, Func < > , Predicate all имеют делегат типа.

Зачем нам нужно Действие: Действие инкапсулирует различное количество параметров и тип типа возвращаемого типа, которые во многих случаях достаточно для разработки приложений. Они представлены в пространстве имен System. Вы можете создавать свой собственный делегат.

Обратите внимание, что существует 17 различных типов Action и Func с нулевым значением до 16 параметризованных общих аргументов.

Действие всегда не имеет возвращаемого значения. Func имеет один параметризованный общий тип возвращаемого значения.

IMHO, Делегат-предикат не нужен, чтобы его можно было определить как его действительно эквивалентный Func, который принимает аргумент arg и возвращает bool.

Ответ 5

Код примера реального мира, который неоднократно запрашивался, уже был предоставлен в более раннем ответе пользователя "Console.WriteLine".

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

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

Что касается ваших точных вопросов,

  • Какая разница между ними

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

  1. Когда использовать делегат или действие

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


class Program
{
    static void Main()
    {
     Dictionary<string, Action> dict = new Dictionary<string, Action>();
     dict["loadFile"] = new Action(LoadFile);
     dict["saveFile"] = new Action(SaveFile);

     dict["loadFile"].Invoke();
     dict["saveFile"].Invoke();
    }

    static void SaveFile()
    {
     Console.WriteLine("File saved!");
    }

    static void LoadFile()
    {
     Console.WriteLine("Loading File...");
    }
}

Еще одно типичное использование для методов обратного вызова. Например, вы должны использовать класс BubbleSort, передавая метод компаратора в качестве делегата в класс, который будет использоваться классом BubbleSort, чтобы ваш код определял логику сравнения, а также заботился обо всем остальном. Это также можно использовать из потоков, которые вы начали, и поток вызывает делегата, когда некоторые промежуточные действия должны быть проинформированы о вашем коде.

Вы можете ссылаться на эту запись SO, чтобы увидеть отличный пример выше. fooobar.com/info/273312/...

  1. Если не использовать делегат или действие

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

  1. Когда они могут быть более убитыми

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

Кроме того, прочитайте этот ответ SO, чтобы увидеть различия между обычными методами, делегаты, чтобы лучше понять, где использовать делегаты/действие/func fooobar.com/info/107157/...