¿Qué es Func<>
y para qué se utiliza?¿Qué es Func, cómo y cuándo se usa?
Respuesta
Func<T>
es un tipo de delegado predefinido para un método que devuelve algún valor del tipo T
.
En otras palabras, puede utilizar este tipo para hacer referencia a un método que devuelve algún valor de T
. P.ej.
public static string GetMessage() { return "Hello world"; }
puede hacer referencia como este
Func<string> f = GetMessage;
Pero también puede representar una función estática de un argumento =) –
@ Ark-kun no, eso no es correcto. La definición de 'Func
No, estoy en lo correcto. 'static int OneArgFunc (esta cadena i) {return 42; } '' Func
Func<T1,R>
y los otros predefinidos genéricos Func
delegados (Func<T1,T2,R>
, Func<T1,T2,T3,R>
y otros) son delegados genéricos que retornan el tipo del último parámetro genérico.
Si tiene una función que necesita devolver tipos diferentes, dependiendo de los parámetros, puede usar un delegado Func
, especificando el tipo de devolución.
Piense en ello como un marcador de posición. Puede ser bastante útil cuando tiene un código que sigue un cierto patrón, pero no necesita estar vinculado a ninguna funcionalidad en particular.
Por ejemplo, considere el método de extensión Enumerable.Select
.
- El patrón es: para cada artículo en una secuencia, seleccionar un valor a partir de ese elemento (por ejemplo, una propiedad) y crear una nueva secuencia que consiste de estos valores.
- marcador de posición es: alguna función de selector que realmente obtiene los valores para la secuencia descrita anteriormente.
Este método toma un Func<T, TResult>
en lugar de cualquier función concreta. Esto permite que se use en cualquier contexto donde se aplica el patrón anterior.
Por ejemplo, supongo que tengo un List<Person>
y solo quiero el nombre de cada persona en la lista. Puedo hacer esto:
var names = people.Select(p => p.Name);
O decir que quiero el edad de cada persona:
var ages = people.Select(p => p.Age);
De inmediato, se puede ver lo que era capaz de aprovechar el código misma que representa una patrón (con Select
) con dos funciones diferentes (p => p.Name
y p => p.Age
).
La alternativa sería escribir una versión diferente de Select
cada vez que desee escanear una secuencia para un tipo diferente de valor.Así que para lograr el mismo efecto que el anterior, que iba a necesitar:
// 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 que actúa como marcador de posición, me libero de tener que escribir el mismo patrón una y otra vez en casos como este.
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:
double sqr(double x) { return x * x; }
Usted puede guardarlo como una especie de función de variables:
Func<double, double> f1 = sqr;
Func<double, double> f2 = x => x * x;
Y luego usar exactamente como lo haría con SQR:
f1(2);
Console.WriteLine(f2(f1(4)));
etc.
Recuerde, sin embargo, que es un delegado, para obtener información más avanzada, consulte la documentación.
Excelente respuesta, pero para la compilación de palabras clave estática es neeed – boctulus
Es solo un delegado genérico predefinido. Al usarlo no necesita declarar a cada delegado. Hay otro delegado predefinido, Action<T, T2...>
, que es el mismo pero devuelve nulo.
Encuentro Func muy útil cuando creo un componente que necesita ser personalizado "sobre la marcha".
Tome este ejemplo muy simple: un componente PrintListToConsole.
Un objeto muy simple que imprime esta lista de objetos a la consola. Desea que el desarrollador que lo usa personalice la salida.
Por ejemplo, quiere permitirle que defina un tipo particular de formato numérico, y así sucesivamente.
Sin Func
En primer lugar, usted tiene que crear una interfaz para una clase que toma la entrada y producir la cadena a imprimir en la consola.
interface PrindListConsoleRender<T> {
String Render(T input);
}
entonces usted tiene que crear el PrintListToConsole clase que tome la interfaz creada anterior y usarlo sobre cada elemento de la lista.
class PrintListToConsole<T> {
private PrindListConsoleRender<T> _renderer;
public void SetRenderer(PrindListConsoleRender<T> r) {
// this is the poin where I can personalize the render mechanism
_renderer = r;
}
public void PrintToConsole(List<T> list) {
foreach (var item in list) {
Console.Write(_renderer.Render(item));
}
}
}
El desarrollador que necesita para utilizar su componente tiene que:
1) implementar la interfaz
2) pasar la clase real a la PrintListToConsole
class myrenderer : PrindListConsoleRender<int> {
public String Render(int input) {
return "Number: " + input;
}
}
class Program {
static void Main(string[] args) {
var list = new List<int> { 1, 2, 3 };
var printer = new PrintListToConsole<int>();
printer.SetRenderer(new myrenderer());
printer.PrintToConsole(list);
string result = Console.ReadLine();
}
}
con la tecla FUNC es mucho más simple
Dentro del componente se define un parámetro de tipo Func que representan una interfaz de una función que toma un parámetro de entrada de tipo T y devolver una cadena (la salida de la consola)
class PrintListToConsole<T> {
private Func<T, String> _renderFunc;
public void SetRenderFunc(Func<T, String> r) {
// this is the point where I can set the render mechanism
_renderFunc = r;
}
public void StampaFunc(List<T> list) {
foreach (var item in list) {
Console.Write(_renderFunc(item));
}
}
}
Cuando el uso de desarrolladores Su componente simplemente pasa al componente la implementación del tipo Func, que es una función que crea la salida para la consola.
class Program {
static void Main(string[] args) {
var list = new Array[1, 2, 3];
var printer = new PrintListToConsole<int>();
printer.SetRenderFunc((o) => "Number:" + o);
string result = Console.ReadLine();
}
}
Func permiten definir una interfaz método genérico sobre la marcha. Define qué tipo son las entradas 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 borrará la ruta. Tuve que agregar el método StampaFunc como se dejó en el código original que impedía su visualización. –
- 1. ¿Qué es una Propiedad de Dependencia y cuándo se usa?
- 2. ¿Qué es GenericParameterHelper y cómo se usa?
- 3. ¿Qué es un "lote" y por qué se usa GO?
- 4. ¿Cuándo se usa StringIO?
- 5. Evaluar: ¿cuándo se usa?
- 6. En Objective C, cuándo se usa alloc y cuándo no es
- 7. ¿Qué es el "modo estricto" y cómo se usa?
- 8. ¿Qué es sharedUserId en Android y cómo se usa?
- 9. ¿Qué es un archivo .SWC Flash y cómo se usa?
- 10. ¿Qué es viewstate en JSF y cómo se usa?
- 11. C# - ¿Qué es un componente y cómo se usa normalmente?
- 12. Qué es una clase de contrato y cómo se usa
- 13. ¿Cuándo se usa realmente ChannelUrl?
- 14. Instanciación explícita: ¿cuándo se usa?
- 15. ¿Qué es 'xmlhttp.setRequestHeader();' y en qué situaciones se usa?
- 16. ¿Qué es LiteralControl? ¿Por qué se usa?
- 17. io_service, ¿por qué y cómo se usa?
- 18. ¿Qué es Ext.Component.initialConfig, qué hace y en qué contexto se usa?
- 19. ¿Qué es Request.InputStream y cuándo usarlo?
- 20. ¿Cuándo/por qué prefijar variables con "$" cuando se usa jQuery?
- 21. ¿Por qué se usa "cuándo" en esta función?
- 22. ¿Cuándo y por qué usa TryUpdateModel en asp.net mvc 2?
- 23. Java - ¿Qué se usa <y cuál es su nombre?
- 24. ¿Cuándo se usa la propiedad @JsonProperty y para qué se utiliza?
- 25. Cuándo se crea un app.config, cuando se usa un app.exe.config y cuál es la diferencia
- 26. ¿Cuándo se usa realmente el paquete savedInstanceState?
- 27. ¿Cuándo se necesita @uncheckedVariance en Scala, y por qué se usa en GenericTraversableTemplate?
- 28. ¿Cuándo se usa una forma de inicio?
- 29. ¿Qué es ICustomTypeDescriptor y cuándo usarlo?
- 30. ¿Qué es SAPI y cuándo lo usarías?
Es solo un atajo para delegados con una firma específica. Para entender completamente las respuestas a continuación, deberá comprender a los delegados ;-) –
En la respuesta de @Oded dice 'Si tiene una función que necesita devolver diferentes tipos, dependiendo de los parámetros, puede usar un delegado de Func, especificando el tipo de retorno. – Lijo