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

В нескольких словах, что можно сказать о Func <>

Я когда-то сидел Func < > , и мне удалось его избежать (пока). Но теперь похоже, что я не могу уклониться от него навсегда. Например, я попробовал Dynamic Linq, но почти все было в терминах Func < > . Я пробовал одну из моих книг (С# 2008/Deitel & Deitel), а также MSDN, но я пока не получаю ее. Они все прыгают прямо в тему.

  • Что можно сказать (в нескольких словах) о Func < >
  • Могу ли я получить некоторые ссылки в Интернете, которые могут помочь мне начать с этого вопроса?

Спасибо за помощь

4b9b3361

Ответ 1

Func<> является общим делегатом - его очень удобно использовать, потому что вам не нужно создавать свой собственный делегат для каждой комбинации типа аргумент/возврат.
Раньше вам приходилось писать что-то вроде:

public delegate long MyDelegate( int number );

public void Method( IEnumerable<int> list, MyDelegate myDelegate )
{
    foreach( var number in list )
    {
        myDelegate( number );
    }
}

Вам нужно было опубликовать свой делегат, чтобы пользователь мог правильно вызвать ваш метод. Особенно, когда вам нужна группа разных делегатов, вы закончили публикацию одного для каждого списка аргументов и возвращаемого типа.
С помощью Func<> вы просто пишете:

public void Method( IEnumerable<int> list, Func<int, long> myDelegate )
{
    foreach( var number in list )
    {
        myDelegate( number );
    }
}

Это означает то же, что и первый пример кода - Func<int, long> определяет делегат, который принимает один целочисленный аргумент и возвращает длинное значение.

Конечно, вы можете использовать более длинные списки параметров: Func<int, int, bool, long> по-прежнему будет возвращать длинное значение, в то время как он принимает два значения int и значение bool. Если вам нужен делегат без возвращаемого значения, вам придется использовать Action<>, который будет иметь пустоту как возвращаемый тип.

EDIT (по запросу): как вызвать метод в моем примере:

Для вызывающего абонента нет разницы между решением с MyDelegate или Func<>. В обоих случаях у него есть три варианта вызова метода:

Использование лямбда-нотации (требуется С# 3.0, вероятно, лучшее решение для коротких методов):

Method( myList, i => i * i );

Используя анонимный метод (требуется С# 2.0):

Method( myList, delegate( int i )
{
    return i * i;
} );

Или с помощью реального метода в качестве аргумента:

Method( myList, Square );

private static long Square( int number )
{
    return number * number;
}

Ответ 2

Func<...> - это семейство типов делегатов, которые возвращают некоторое значение и принимают несколько аргументов; например:

  • Func<int,bool> - это просто что-то, что принимает int и возвращает bool (возврат всегда в конце); например, предикат:

    int[] data = {1,2,3,4,5};
    var odd = data.Where(i => i % 2 == 0);
    
  • Func<string> - это метод, который возвращает строку, например () => "hello world";.

  • Func<DateDtime, TimeSpan, DateTime> может быть чем-то вроде (when,howLong) => when + howLong;

Аналогично существует Action<...>, который делает то же самое, но без возвращаемого типа.

В Func<...> нет ничего волшебного - это просто более простой способ выражения делегатов, а: использование дженериков (полезно для LINQ) или b: вам не нужно искать, какие аргументы; если тип делегата является чем-то неясным (например, PipeStreamImpersonationWorker), может быть трудно понять, что нужно; если бы это было выражено как сопоставимое Action, было бы ясно, что он не принимает никаких параметров и возвращает void.

Ответ 3

Это может помочь. Предположим, что каждый раз, когда вы видите Func<int, string>, вы думаете:

interface IFuncIntString
{
    string Invoke(int x);
}

То есть, делегат является объектом, реализующим этот интерфейс. Он имеет один метод Invoke, который принимает int и возвращает строку.

Теперь добавьте к этому функцию, которую вы можете опустить "Вызывать" при вызове, и у вас есть делегат.

Ответ 4

Func<int> (например) является типом (таким образом, что string является типом). Таким образом, вы используете его для объявления переменных, полей, параметров и т.д.

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

Func<int> f = () => DateTime.Now.Second;

// elsewhere...

Console.WriteLine( f() );

Обратите внимание, как вы можете называть его точно так же, как метод. Существует много перегруженных версий Func для поддержки разных параметров. Аргументом последнего типа является тип возвращаемого значения.

Func<int, string> quoteInt = n => "\"" + n + "\"";

Console.WriteLine( quoteInt(3) );

Func - тип делегата. Вы можете заявить о себе, но проще использовать Func. Если вы хотите вернуть void, используйте Action вместо Func. Вам нужно только объявить пользовательские делегаты, если вам нужны параметры out или ref.

При назначении лямбда для Func вы можете обратиться к локальным переменным. Это чрезвычайно мощно; это означает, что a Func больше, чем просто код; он имеет данные. Таким образом, он похож на объект с единственным методом (который это технически - метод называется Invoke, и компилятор неявно вызывает этот метод для вас, когда вы вызываете делегата).

Синтаксис () => может быть помещен перед любым выражением, чтобы сказать: "Не делайте этого сейчас, задерживайте его до конца". Он позволяет инициализировать делегат, фиксирующий задержку вычислений. И тогда синтаксис () может быть размещен после делегирования, чтобы фактически вызвать вычисление. Таким образом, суффикс () является видом противоположности префикса () =>.

Ответ 5

Вы можете начать с 101 Linq Samples.

Короче говоря, Func<> является делегатом, где последним типом является тип возвращаемого значения.

Итак, Func<int,bool> - это делегат, который принимает параметр int и возвращает bool.

Ответ 6

Func <..., T > является делегатом. где T - тип возвращаемого типа, а все остальные - входные параметры.

Ответ 7

Если вы когда-либо использовали оператор = > в С#, и, вероятно, вы уже использовали Funcs. Вы просто не указали их явно.

Итак, если вы напишете инструкцию типа

var peopleWhoLikeBlue = people.Where(person => person.FavoriteColor == "Blue");

вы передаете Func<Person, bool> в метод Where().

Если вы хотите быть многословным, вы можете переписать этот оператор следующим образом:

Func<Person, bool> favoriteColorIsBlue = person => person.FavoriteColor == "Blue";
var peopleWhoLikeBlue = people.Where(favoriteColorIsBlue);

И вы получите тот же результат.