В чем разница между Func <string, string> и delegate?

81

Я вижу делегатов в двух формах:

A. Func<string, string> convertMethod = lambda 

B. public delegate string convertMethod(string value);

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

Dietpixel
источник

Ответы:

74

Прежде всего, ваши два примера делают две совершенно разные вещи. Первый - это объявление общей переменной-делегата и присвоение ей значения, второй - просто определение delegateтипа. Ваш пример, более полный, будет:

public static class Program
{
    // you can define your own delegate for a nice meaningful name, but the
    // generic delegates (Func, Action, Predicate) are all defined already
    public delegate string ConvertedMethod(string value);

    public static void Main()
    {
        // both work fine for taking methods, lambdas, etc.
        Func<string, string> convertedMethod = s => s + ", Hello!";
        ConvertedMethod convertedMethod2 = s => s + ", Hello!";
    }
}

Но что более важно, оба Func<string,string>и delegate string convertMethod(string)могут содержать одни и те же определения методов, будь то методы, анонимные методы или лямбда-выражения.

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

Джеймс Майкл Хэйр
источник
1
Еще более ясным примером может быть тот Func<int, string>, который показывает, что форма есть Func<arg1, result>.
silvalli
6
Думаю, стоит отметить, что Func и Action являются делегатами. Когда вы это знаете, это кажется очевидным, но я волновался об этом факте, прежде чем взглянул на подпись Func. Поэтому, когда вы говорите: «Прежде всего, ваши два примера делают две совершенно разные вещи». можно также сказать: «Func - делегат».
Falk
12

Образец кода, который у вас есть, немного сбивает с толку, поэтому позвольте мне попытаться прояснить его. Следующие 2 элемента являются объявлениями делегатов. Их легко обнаружить, потому что они всегда будут содержать delegateключевое слово

public delegate TReturn Func<TArg, TReturn>(Targ value);
public delegate string convertMethod(string value);

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

Func<string, string> local = lambda;

Однако приведенный выше код не ограничивается использованием только лямбда-выражений. Значением также может быть совместимая группа методов или другое значение делегата.

Еще один момент, на который следует обратить внимание, заключается в том, что хотя Func<string, string>и convertMethodоба являются делегатами с одинаковыми подписями, их значения не могут быть преобразованы друг в друга. Например, следующее недопустимо

Func<string, string> local1 = ...;
convertMethod local2 = local1; // Error!!!
ДжаредПар
источник
8

Из MSDN ,

В версиях C # до 2.0 единственным способом объявить делегат было использование именованных методов. В C # 2.0 появились анонимные методы, а в C # 3.0 и более поздних версиях лямбда-выражения заменяют анонимные методы в качестве предпочтительного способа написания встроенного кода.

и

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

Вас также может заинтересовать этот SO-ответ по ключевому слову делегата и лямбда-выражению .

Кроме того, в MSDN есть хорошая статья о лямбда-выражениях :

delegate int del(int i);
static void Main(string[] args)
{
    del myDelegate = x => x * x;
    int j = myDelegate(5); //j = 25
}

Обратите внимание, что в предыдущем примере подпись делегата имеет один неявно типизированный входной параметр типа int и возвращает int. Лямбда-выражение можно преобразовать в делегат этого типа, поскольку он также имеет один входной параметр (x) и возвращаемое значение, которое компилятор может неявно преобразовать в тип int. (Выведение типа более подробно обсуждается в следующих разделах.) Когда делегат вызывается с использованием входного параметра 5, он возвращает результат 25.

Сообщество
источник
Вы также можете опустить параметры из лямбды. () => Console.Writeline ("параметр без лямбда")
доктор Део
Действие test = () => Console.Writeline ("параметр без лямбда"); test.Invoke ();
Dr Deo
5

A инициализирует экземпляр делегата (который может быть вызван немедленно). Это переменная типа Func <string, string>.

B указывает определение делегата (его подпись). Его можно использовать для определения переменных типа convertMethod .

fparadis2
источник