Es solo un atajo para delegados con una firma específica. Para comprender completamente las respuestas a continuación, deberá comprender a los delegados ;-)
Theo Lenndorff
2
En la respuesta de @Oded diceIf 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
Respuestas:
76
Func<T>es un tipo de delegado predefinido para un método que devuelve algún valor del tipo T.
En otras palabras, puede usar este tipo para hacer referencia a un método que devuelve algún valor de T. P.ej
Pero también puede representar una función estática de un argumento =)
Ark-kun
2
@ Ark-kun no, eso no es correcto. La definición de Func<T>es delegate TResult Func<out TResult>(). Sin argumentos. Func<T1, T2>sería una función que toma un argumento.
Brian Rasmussen
4
No, estoy en lo correcto. static int OneArgFunc(this string i) { return 42; }Func<int> f = "foo".OneArgFunc;. =)
Ark-kun
1
Ese es un método de extensión que es especial.
Brian Rasmussen
Lo único especial es el Extensionatributo que solo leen los compiladores de C # / VB.Net, no CLR. Básicamente, los métodos de instancia (a diferencia de las funciones estáticas) tienen un parámetro 0 oculto "este". Entonces, el método de instancia de 1 argumento es muy similar a la función estática de 2 argumentos. Luego, tenemos delegados que almacenan el objeto de destino y el puntero de función . Los delegados pueden almacenar el primer argumento en destino o no hacerlo.
Ark-kun
87
Piense en ello como un marcador de posición. Puede ser muy útil cuando tiene un código que sigue un patrón determinado pero no necesita estar vinculado a ninguna funcionalidad en particular.
Por ejemplo, considere el Enumerable.Selectmétodo de extensión.
El patrón es: para cada elemento de una secuencia, seleccione algún valor de ese elemento (por ejemplo, una propiedad) y cree una nueva secuencia que conste de estos valores.
El marcador de posición es: alguna función de selector que realmente obtiene los valores para la secuencia descrita anteriormente.
Este método toma una Func<T, TResult>función concreta en lugar de cualquier. Esto permite que se use en cualquier contexto donde se aplique el patrón anterior.
Entonces, por ejemplo, digamos que tengo un List<Person>y quiero solo el nombre de cada persona en la lista. Puedo hacer esto:
var names = people.Select(p => p.Name);
O di que quiero la edad de cada persona:
var ages = people.Select(p => p.Age);
De inmediato, puede ver cómo pude aprovechar el mismo código que representa un patrón (con Select) con dos funciones diferentes ( p => p.Namey p => p.Age).
La alternativa sería escribir una versión diferente de Selectcada vez que desee escanear una secuencia en busca de un tipo de valor diferente. Entonces, para lograr el mismo efecto que el anterior, necesitaría:
// 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);
Con un delegado actuando como marcador de posición, me libero de tener que escribir el mismo patrón una y otra vez en casos como este.
Luego, debe crear la clase PrintListToConsole<T>que toma la interfaz creada anteriormente y la usa sobre cada elemento de la lista.
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));}}}
El desarrollador que necesita usar su componente debe:
Dentro del componente, define un parámetro de tipo Func<T,String>que representa una interfaz de una función que toma un parámetro de entrada de tipo T y devuelve una cadena (la salida para la consola)
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));}}}
Cuando el desarrollador usa su componente, simplemente le pasa al componente la implementación del Func<T, String>tipo, que es una función que crea la salida para la consola.
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>le permite definir una interfaz de método genérico sobre la marcha.
Usted define qué tipo es la entrada y qué tipo es la salida. Simple y conciso.
Gracias por publicar este Marco. Ciertamente, me ha ayudado. He estado tratando de entender func por un tiempo y también lo uso activamente en mi programación. Este ejemplo despejará el camino. Tuve que agregar el método StampaFunc ya que se omitió en el código original, lo que impedía que se mostrara.
Siwoku Adeola
1
Creo que hay una línea perdida en la muestra de Func, ¿dónde está la llamada a la función de impresión o StampaFunc?
Bashar Abu Shamaa
11
Func<T1,R>y los otros Funcdelegados genéricos predefinidos ( Func<T1,T2,R>, Func<T1,T2,T3,R>y otros) son delegados genéricos que devuelven el tipo del último parámetro genérico.
Si tiene una función que necesita devolver diferentes tipos, dependiendo de los parámetros, puede usar un Funcdelegado, especificando el tipo de retorno.
Es solo un delegado genérico predefinido. Al usarlo, no necesita declarar a todos los delegados. Hay otro delegado predefinido Action<T, T2...>, que es el mismo pero devuelve vacío.
Tal vez no sea demasiado tarde para agregar información.
Suma:
El Func es un delegado personalizado definido en el espacio de nombres del sistema que le permite apuntar a un método con la misma firma (como lo hacen los delegados), usando 0 a 16 parámetros de entrada y que debe devolver algo.
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.
Respuestas:
Func<T>
es un tipo de delegado predefinido para un método que devuelve algún valor del tipoT
.En otras palabras, puede usar este tipo para hacer referencia a un método que devuelve algún valor de
T
. P.ejpuede ser referenciado así
fuente
Func<T>
esdelegate TResult Func<out TResult>()
. Sin argumentos.Func<T1, T2>
sería una función que toma un argumento.static int OneArgFunc(this string i) { return 42; }
Func<int> f = "foo".OneArgFunc;
. =)Extension
atributo que solo leen los compiladores de C # / VB.Net, no CLR. Básicamente, los métodos de instancia (a diferencia de las funciones estáticas) tienen un parámetro 0 oculto "este". Entonces, el método de instancia de 1 argumento es muy similar a la función estática de 2 argumentos. Luego, tenemos delegados que almacenan el objeto de destino y el puntero de función . Los delegados pueden almacenar el primer argumento en destino o no hacerlo.Piense en ello como un marcador de posición. Puede ser muy útil cuando tiene un código que sigue un patrón determinado pero no necesita estar vinculado a ninguna funcionalidad en particular.
Por ejemplo, considere el
Enumerable.Select
método de extensión.Este método toma una
Func<T, TResult>
función concreta en lugar de cualquier. Esto permite que se use en cualquier contexto donde se aplique el patrón anterior.Entonces, por ejemplo, digamos que tengo un
List<Person>
y quiero solo el nombre de cada persona en la lista. Puedo hacer esto:O di que quiero la edad de cada persona:
De inmediato, puede ver cómo pude aprovechar el mismo código que representa un patrón (con
Select
) con dos funciones diferentes (p => p.Name
yp => p.Age
).La alternativa sería escribir una versión diferente de
Select
cada vez que desee escanear una secuencia en busca de un tipo de valor diferente. Entonces, para lograr el mismo efecto que el anterior, necesitaría:Con un delegado actuando como marcador de posición, me libero de tener que escribir el mismo patrón una y otra vez en casos como este.
fuente
Func<T1, T2, ..., Tn, Tr>
representa una función que toma argumentos (T1, T2, ..., Tn) y devuelve Tr.Por ejemplo, si tiene una función:
Puede guardarlo como una especie de variable de función:
Y luego use exactamente como usaría sqr:
etc.
Sin embargo, recuerde que es un delegado; para obtener información más avanzada, consulte la documentación.
fuente
Encuentro
Func<T>
muy útil cuando creo un componente que necesita ser personalizado "sobre la marcha".Tome este ejemplo muy simple: un
PrintListToConsole<T>
componente.Un objeto muy simple que imprime esta lista de objetos en la consola. Desea permitir que el desarrollador que lo usa personalice la salida.
Por ejemplo, desea permitirle definir un tipo particular de formato de número, etc.
Sin Func
Primero, debe crear una interfaz para una clase que toma la entrada y produce la cadena para imprimir en la consola.
Luego, debe crear la clase
PrintListToConsole<T>
que toma la interfaz creada anteriormente y la usa sobre cada elemento de la lista.El desarrollador que necesita usar su componente debe:
implementar la interfaz
pasar la clase real al
PrintListToConsole
Usar Func es mucho más sencillo
Dentro del componente, define un parámetro de tipo
Func<T,String>
que representa una interfaz de una función que toma un parámetro de entrada de tipo T y devuelve una cadena (la salida para la consola)Cuando el desarrollador usa su componente, simplemente le pasa al componente la implementación del
Func<T, String>
tipo, que es una función que crea la salida para la consola.Func<T>
le permite definir una interfaz de método genérico sobre la marcha. Usted define qué tipo es la entrada y qué tipo es la salida. Simple y conciso.fuente
Func<T1,R>
y los otrosFunc
delegados genéricos predefinidos (Func<T1,T2,R>
,Func<T1,T2,T3,R>
y otros) son delegados genéricos que devuelven el tipo del último parámetro genérico.Si tiene una función que necesita devolver diferentes tipos, dependiendo de los parámetros, puede usar un
Func
delegado, especificando el tipo de retorno.fuente
Es solo un delegado genérico predefinido. Al usarlo, no necesita declarar a todos los delegados. Hay otro delegado predefinido
Action<T, T2...>
, que es el mismo pero devuelve vacío.fuente
Tal vez no sea demasiado tarde para agregar información.
Suma:
El Func es un delegado personalizado definido en el espacio de nombres del sistema que le permite apuntar a un método con la misma firma (como lo hacen los delegados), usando 0 a 16 parámetros de entrada y que debe devolver algo.
Nomenclatura y uso:
Definición:
Dónde se usa:
Se utiliza en expresiones lambda y métodos anónimos.
fuente