У чому різниця між Func <рядок, рядок> та делегатом?


81

Я бачу делегатів у двох формах:

A. Func<string, string> convertMethod = lambda 

B. public delegate string convertMethod(string value);

Я не знаю, яка насправді різниця між цими двома. Вони обоє делегати? Я вважаю, що перший використовував би лямбда, а другий повинен був мати метод, щоб насправді виконати роботу. Я теж можу розгубитися.


Відповіді:


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 - делегат".
Фальк

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 ("параметр менше лямбда")
доктор Део

Тест дії = () => Console.Writeline ("параметр менше лямбда"); test.Invoke ();
Доктор Део,

5

Ініціалізує екземпляр делегата (який може бути викликаний відразу). Це змінна типу Func <рядок, рядок>.

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

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