Это просто ярлык для делегатов с определенной подписью. Чтобы полностью понять приведенные ниже ответы, вам необходимо понять делегатов ;-)
Тео Ленндорф,
2
В ответе @Oded написаноIf you have a function that needs to return different types, depending on the parameters, you can use a Func delegate, specifying the return type.
LCJ
Ответы:
76
Func<T>- это предопределенный тип делегата для метода, который возвращает некоторое значение типа T.
Другими словами, вы можете использовать этот тип для ссылки на метод, который возвращает некоторое значение T. Например
Но он также может представлять статическую функцию с одним аргументом =)
Арк-кун
2
@ Арк-кун, нет, это не так. Определение Func<T>есть delegate TResult Func<out TResult>(). Никаких аргументов. Func<T1, T2>будет функцией, которая принимает один аргумент.
Брайан Расмуссен
4
Нет, я прав. static int OneArgFunc(this string i) { return 42; }Func<int> f = "foo".OneArgFunc;. =)
Ark-kun
1
Это особенный метод расширения.
Брайан Расмуссен
Единственная особенность этого Extensionатрибута - это атрибут, который читается только компиляторами C # / VB.Net, а не CLR. По сути, методы экземпляра (в отличие от статических функций) имеют скрытый 0-й параметр this. Итак, метод экземпляра с одним аргументом очень похож на статическую функцию с двумя аргументами. Затем у нас есть делегаты, которые хранят целевой объект и указатель на функцию . Делегаты могут хранить первый аргумент в target или не делать этого.
Ark-kun
87
Думайте об этом как о заполнителе. Это может быть весьма полезно, если у вас есть код, который следует определенному шаблону, но не должен быть привязан к какой-либо конкретной функции.
Например, рассмотрим Enumerable.Selectметод расширения.
Шаблон является: для каждого элемента в последовательности, выберите некоторое значение из этого элемента (например, свойства) и создать новую последовательность , состоящую из этих значений.
Заполнитель является: некоторая функция селектора , который на самом деле получает значения для последовательности описанной выше.
Этот метод принимает Func<T, TResult>вместо какой-либо конкретной функции. Это позволяет использовать его в любом контексте, где применяется вышеуказанный шаблон.
Так, например, скажем, у меня есть List<Person>и мне нужно только имя каждого человека в списке. Я могу это сделать:
var names = people.Select(p => p.Name);
Или скажите, что я хочу возраст каждого человека:
var ages = people.Select(p => p.Age);
Сразу видно, как мне удалось использовать один и тот же код, представляющий шаблон (с Select) с двумя разными функциями ( p => p.Nameи p => p.Age).
Альтернативой может быть написание новой версии Selectкаждого случая, когда вы хотите сканировать последовательность для другого типа значения. Итак, чтобы добиться того же эффекта, что и выше, мне понадобятся:
// Presumably, the code inside these two methods would look almost identical;// the only difference would be the part that actually selects a value// based on a Person.var names =GetPersonNames(people);var ages =GetPersonAges(people);
Когда делегат выступает в качестве заполнителя, я избавляюсь от необходимости повторять один и тот же шаблон снова и снова в подобных случаях.
Отличный ответ, но для составления статического ключевого слова необходим
boctulus
16
Я считаю Func<T>очень полезным, когда создаю компонент, который нужно персонализировать «на лету».
Возьмем этот очень простой пример: PrintListToConsole<T>компонент.
Очень простой объект, который выводит этот список объектов на консоль. Вы хотите позволить разработчику, который его использует, персонализировать вывод.
Например, вы хотите позволить ему определять определенный тип числового формата и так далее.
Без Func
Во-первых, вы должны создать интерфейс для класса, который принимает входные данные и создает строку для вывода на консоль.
Затем вам нужно создать класс, PrintListToConsole<T>который берет ранее созданный интерфейс и использует его для каждого элемента списка.
classPrintListToConsole<T>{privatePrintListConsoleRender<T> _renderer;publicvoidSetRenderer(PrintListConsoleRender<T> r){// this is the point where I can personalize the render mechanism
_renderer = r;}publicvoidPrintToConsole(List<T>list){foreach(var item inlist){Console.Write(_renderer.Render(item));}}}
Разработчик, которому необходимо использовать ваш компонент, должен:
Внутри компонента вы определяете параметр типа, Func<T,String>который представляет интерфейс функции, которая принимает входной параметр типа T и возвращает строку (вывод для консоли)
classPrintListToConsole<T>{privateFunc<T,String> _renderFunc;publicvoidSetRenderFunc(Func<T,String> r){// this is the point where I can set the render mechanism
_renderFunc = r;}publicvoidPrint(List<T>list){foreach(var item inlist){Console.Write(_renderFunc(item));}}}
Когда разработчик использует ваш компонент, он просто передает компоненту реализацию Func<T, String>типа, то есть функцию, которая создает вывод для консоли.
classProgram{staticvoidMain(string[] args){varlist=newList<int>{1,2,3};// should be a list as the method signature expectsvar printer =newPrintListToConsole<int>();
printer.SetRenderFunc((o)=>"Number:"+ o);
printer.Print(list);string result =Console.ReadLine();}}
Func<T>позволяет определять интерфейс универсального метода на лету.
Вы определяете, к какому типу относятся входные и выходные данные. Просто и лаконично.
Спасибо, что разместили это, Марко. Мне это действительно помогло. Некоторое время я пытался понять func, а также активно использую его в своем программировании. Этот пример очистит путь. Мне пришлось добавить метод StampaFunc, поскольку он был исключен в исходном коде, что не позволяло ему отображаться.
Siwoku Adeola
1
Я думаю, что в примере Func пропущена строка. Где вызов функции печати или StampaFunc?
Башар Абу Шамаа
11
Func<T1,R>и другие предопределенные общие Funcделегаты ( Func<T1,T2,R>, Func<T1,T2,T3,R>и другие) являются общими делегатами , которые возвращают тип последнего родового параметра.
Если у вас есть функция, которая должна возвращать разные типы в зависимости от параметров, вы можете использовать Funcделегат, указав тип возвращаемого значения.
Это просто предопределенный универсальный делегат. Используя его, вам не нужно объявлять каждого делегата. Есть еще один предопределенный делегат, Action<T, T2...>который такой же, но возвращает void.
Func - это настраиваемый делегат, определенный в пространстве имен System, который позволяет вам указывать на метод с той же сигнатурой (что и делегаты), используя от 0 до 16 входных параметров, которые должны что-то возвращать.
If you have a function that needs to return different types, depending on the parameters, you can use a Func delegate, specifying the return type.
Ответы:
Func<T>
- это предопределенный тип делегата для метода, который возвращает некоторое значение типаT
.Другими словами, вы можете использовать этот тип для ссылки на метод, который возвращает некоторое значение
T
. Напримерна это можно ссылаться
источник
Func<T>
естьdelegate TResult Func<out TResult>()
. Никаких аргументов.Func<T1, T2>
будет функцией, которая принимает один аргумент.static int OneArgFunc(this string i) { return 42; }
Func<int> f = "foo".OneArgFunc;
. =)Extension
атрибута - это атрибут, который читается только компиляторами C # / VB.Net, а не CLR. По сути, методы экземпляра (в отличие от статических функций) имеют скрытый 0-й параметр this. Итак, метод экземпляра с одним аргументом очень похож на статическую функцию с двумя аргументами. Затем у нас есть делегаты, которые хранят целевой объект и указатель на функцию . Делегаты могут хранить первый аргумент в target или не делать этого.Думайте об этом как о заполнителе. Это может быть весьма полезно, если у вас есть код, который следует определенному шаблону, но не должен быть привязан к какой-либо конкретной функции.
Например, рассмотрим
Enumerable.Select
метод расширения.Этот метод принимает
Func<T, TResult>
вместо какой-либо конкретной функции. Это позволяет использовать его в любом контексте, где применяется вышеуказанный шаблон.Так, например, скажем, у меня есть
List<Person>
и мне нужно только имя каждого человека в списке. Я могу это сделать:Или скажите, что я хочу возраст каждого человека:
Сразу видно, как мне удалось использовать один и тот же код, представляющий шаблон (с
Select
) с двумя разными функциями (p => p.Name
иp => p.Age
).Альтернативой может быть написание новой версии
Select
каждого случая, когда вы хотите сканировать последовательность для другого типа значения. Итак, чтобы добиться того же эффекта, что и выше, мне понадобятся:Когда делегат выступает в качестве заполнителя, я избавляюсь от необходимости повторять один и тот же шаблон снова и снова в подобных случаях.
источник
Func<T1, T2, ..., Tn, Tr>
представляет функцию, которая принимает (T1, T2, ..., Tn) аргументов и возвращает Tr.Например, если у вас есть функция:
Вы можете сохранить его как некую функцию-переменную:
А затем используйте точно так же, как если бы вы использовали sqr:
и т.п.
Однако помните, что это делегат, для получения более подробной информации обратитесь к документации.
источник
Я считаю
Func<T>
очень полезным, когда создаю компонент, который нужно персонализировать «на лету».Возьмем этот очень простой пример:
PrintListToConsole<T>
компонент.Очень простой объект, который выводит этот список объектов на консоль. Вы хотите позволить разработчику, который его использует, персонализировать вывод.
Например, вы хотите позволить ему определять определенный тип числового формата и так далее.
Без Func
Во-первых, вы должны создать интерфейс для класса, который принимает входные данные и создает строку для вывода на консоль.
Затем вам нужно создать класс,
PrintListToConsole<T>
который берет ранее созданный интерфейс и использует его для каждого элемента списка.Разработчик, которому необходимо использовать ваш компонент, должен:
реализовать интерфейс
передать настоящий класс
PrintListToConsole
Используя Func, это намного проще
Внутри компонента вы определяете параметр типа,
Func<T,String>
который представляет интерфейс функции, которая принимает входной параметр типа T и возвращает строку (вывод для консоли)Когда разработчик использует ваш компонент, он просто передает компоненту реализацию
Func<T, String>
типа, то есть функцию, которая создает вывод для консоли.Func<T>
позволяет определять интерфейс универсального метода на лету. Вы определяете, к какому типу относятся входные и выходные данные. Просто и лаконично.источник
Func<T1,R>
и другие предопределенные общиеFunc
делегаты (Func<T1,T2,R>
,Func<T1,T2,T3,R>
и другие) являются общими делегатами , которые возвращают тип последнего родового параметра.Если у вас есть функция, которая должна возвращать разные типы в зависимости от параметров, вы можете использовать
Func
делегат, указав тип возвращаемого значения.источник
Это просто предопределенный универсальный делегат. Используя его, вам не нужно объявлять каждого делегата. Есть еще один предопределенный делегат,
Action<T, T2...>
который такой же, но возвращает void.источник
Может, еще не поздно добавить инфу.
Сумма:
Func - это настраиваемый делегат, определенный в пространстве имен System, который позволяет вам указывать на метод с той же сигнатурой (что и делегаты), используя от 0 до 16 входных параметров, которые должны что-то возвращать.
Номенклатура и способы использования:
Определение:
Где используется:
Он используется в лямбда-выражениях и анонимных методах.
источник