Я видел Func <> для когда-то теперь, и я имею, умеют избежать его (на данный момент). Но, теперь похоже, что я не могу избежать его навсегда. Например, я попробовал Динамический Linq, но почти все было с точки зрения Func <>. Я попробовал одну из своей книги (C# 2008/Deitel&Deitel) и также MSDN, но я еще не получаю его. Они все переходят прямо в предмете.
Спасибо за помощь
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
определяет делегата который принимает один целочисленный аргумент и возвращает длинное значение.
Конечно, вы также можете использовать более длинные списки параметров: Func
по-прежнему будет возвращать значение long , хотя для этого потребуется два int и значение bool . Если вам нужен делегат без возвращаемого значения, вам нужно будет использовать Action <>
, у которого будет void в качестве возвращаемого типа.
РЕДАКТИРОВАТЬ (по запросу): Как вызвать метод в моем примере :
Для вызывающей стороны нет разницы между решением с MyDelegate
или Func <>
. В обоих случаях у него есть три варианта вызова метода:
Использование лямбда-нотации (требуется C # 3.0, вероятно, лучшее решение для коротких методов):
Method( myList, i => i * i );
Используя анонимный метод (требуется C # 2.0):
Method( myList, delegate( int i )
{
return i * i;
} );
Или используя в качестве аргумента реальный метод:
Method( myList, Square );
private static long Square( int number )
{
return number * number;
}
Func <...>
- это семейство типов делегатов, которые возвращают некоторое значение и принимают некоторое количество аргументов; например:
Func
- это просто что-то, что принимает int и возвращает bool (возврат всегда в конце); например, предикат:
int [] data = {1,2,3,4,5};
var odd = data.Where (i => i% 2 == 0); {{ 1}}
Func
- это метод, который возвращает строку, например () => "hello world";
.
Func
может иметь вид (when, howLong) => when + howLong;
Аналогично есть Action <...>
который делает то же самое, но без возвращаемого типа.
В Func <...>
нет ничего волшебного - это просто более простой способ выражения делегатов, в то время как a: с использованием универсальных шаблонов (полезно для LINQ) или b: вам не нужно искать каковы аргументы; если тип делегата непонятен (например, PipeStreamImpersonationWorker
), может быть трудно понять, что для этого нужно; если бы это было выражено как сопоставимое Action
, было бы ясно, что оно не принимает никаких параметров и возвращает void
.
Вы можете начать с 101 примеров Linq .
Короче говоря, Func <>
- это делегат, в котором последний параметр типа является возвращаемым типом.
Итак, Func
- это делегат, который принимает параметр int
и возвращает bool
.
Если вы когда-либо использовали оператор => в C # и, вероятно, использовали, вы уже использовали Funcs. Вы просто не объявляли их явно.
Итак, если вы пишете такой оператор, как
var peopleWhoLikeBlue = people.Where(person => person.FavoriteColor == "Blue");
, вы передаете Func
в метод Where ().
Если вы хотите быть многословным, вы можете переписать это утверждение следующим образом:
Func<Person, bool> favoriteColorIsBlue = person => person.FavoriteColor == "Blue";
var peopleWhoLikeBlue = people.Where(favoriteColorIsBlue);
И вы получите тот же результат.
Это может помочь. Предположим, каждый раз, когда вы видите Func
, вы думаете про себя:
interface IFuncIntString
{
string Invoke(int x);
}
То есть делегат - это объект, реализующий этот интерфейс. У него есть единственный метод Invoke, который принимает int и возвращает строку.
Теперь добавьте к этому функцию, позволяющую опустить «Вызов» при вызове, и у вас есть делегат.
Func
(например) - это тип (аналогично тому, как строка
является типом). Таким образом, вы используете его для объявления переменных, полей, параметров и так далее.
Он представляет собой вычисление, которое может быть выполнено всякий раз, когда вы запрашиваете ответ:
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
вы можете ссылаться на локальные переменные. Это очень мощно; это означает, что Func
- это больше, чем просто код; у него есть данные. Так что это похоже на объект с одним методом (что технически так и есть - метод называется Invoke
, и компилятор неявно вызывает этот метод для вас, когда вы вызываете делегат).
Синтаксис () =>
может быть помещен перед любым выражением, чтобы сказать «не делайте этого сейчас, отложите это на потом». Это позволяет вам инициализировать делегата, фиксирующего отложенное вычисление. И затем синтаксис ()
может быть помещен после делегата, чтобы фактически запустить вычисление.Таким образом, суффикс ()
является своего рода противоположностью префиксу () =>
.
Func <..., T> является делегатом. где T - возвращаемый тип, а все остальные - входные параметры.