В нескольких словах, что можно сказать о Func <>
Я когда-то сидел Func < > , и мне удалось его избежать (пока). Но теперь похоже, что я не могу уклониться от него навсегда. Например, я попробовал Dynamic Linq, но почти все было в терминах Func < > . Я пробовал одну из моих книг (С# 2008/Deitel & Deitel), а также MSDN, но я пока не получаю ее. Они все прыгают прямо в тему.
- Что можно сказать (в нескольких словах) о Func < >
- Могу ли я получить некоторые ссылки в Интернете, которые могут помочь мне начать с этого вопроса?
Спасибо за помощь
Ответы
Ответ 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);
И вы получите тот же результат.