2010-04-18 3 views
20

He estado viendo Func <> por algún tiempo, y he logrado evitarlo (por ahora). Pero, ahora parece que no puedo esquivarlo para siempre. Por ejemplo, probé Dynamic Linq, pero casi todo estaba en términos de Func <>. Probé uno de mis libros (C# 2008/Deitel & Deitel) y también MSDN, pero aún no lo recibo. Todos saltan directamente en el tema.En pocas palabras, ¿qué se puede decir sobre Func <>

  1. Lo que se puede decir (en pocas palabras) sobre Func <>
  2. ¿Puedo obtener algunos enlaces en la web que puede me refiero a que la materia?

Gracias por ayudar a

+1

El libro de Jon Skeet sobre c sharp tiene unos excelentes capítulos sobre esto y por qué es tan importante para las funciones lambda y linq. –

+0

No hay nada de miedo ni razón para evitar, Func o delegados genéricos: simplemente son delegados que representan métodos generales que toman una cierta cantidad de argumentos. – thecoop

+0

Es posible que desee consultar las diversas preguntas de Func en SO: http://stackoverflow.com/questions/tagged/func –

Respuesta

33

Func<> es un delegado genérico, es muy conveniente de usar, porque no tiene que crear su propio delegado para cada combinación de argumento/tipo de retorno.
Anteriormente, había que escribir algo como:

public delegate long MyDelegate(int number); 

public void Method(IEnumerable<int> list, MyDelegate myDelegate) 
{ 
    foreach(var number in list) 
    { 
     myDelegate(number); 
    } 
} 

Había que publicar su delegado para que un usuario puede llamar a su método correctamente. Especialmente cuando necesita un grupo de delegados diferentes, terminó publicando uno para cada lista de argumentos y tipo de devolución.
Con Func<> que acaba de escribir:

public void Method(IEnumerable<int> list, Func<int, long> myDelegate) 
{ 
    foreach(var number in list) 
    { 
     myDelegate(number); 
    } 
} 

significa lo mismo como el primer ejemplo de código - Func<int, long> define un delegado que toma un argumento entero y devuelve un valor de largo.

Por supuesto se puede utilizar listas de parámetros más largos, también: Func<int, int, bool, long> todavía volverá mucho valor mientras que se requieren dos enteros y un valorbool. Si desea un delegado sin valor devuelto, deberá usar Action<>, que tendrá void como tipo de devolución.

EDITAR (por petición): cómo llamar al método en mi ejemplo:

Para la persona que llama, no hay diferencia entre la solución con MyDelegate o Func<>. En ambos casos se dispone de tres opciones para llamar al método:

Utilizando una notación lambda (C# 3.0 requerido, probablemente la mejor solución para los métodos cortos):

Method(myList, i => i * i); 

Mediante el uso de un método anónimo (C# 2.0 requerido):

Method(myList, delegate(int i) 
{ 
    return i * i; 
}); 

o utilizando un método real como un argumento:

Method(myList, Square); 

private static long Square(int number) 
{ 
    return number * number; 
} 
+0

¡Muy buena explicación! – John

+0

Buena explicación. Sería bueno incluir un ejemplo de usar/llamar al Método también. –

+0

@Metro: Agregué algunos ejemplos de cómo llamar al método – tanascius

3

Puede comenzar con 101 Linq Samples.

En resumen, Func<> es un delegado donde el último tipo de parámetro es el tipo de devolución.

Por lo tanto, Func<int,bool> es un delegado que toma un parámetro int y devuelve un bool.

12

Func<...> es familia de tipos de delegado, que devuelven cierto valor y toman un número de argumentos; por ejemplo:

  • Func<int,bool> es simplemente algo que toma un int y devuelve un bool (el retorno es siempre al final); por ejemplo un predicado:

    int[] data = {1,2,3,4,5}; 
    var odd = data.Where(i => i % 2 == 0); 
    
  • Func<string> es un método que devuelve cadena, como () => "hello world";.

  • Func<DateDtime, TimeSpan, DateTime> podría ser algo como (when,howLong) => when + howLong;

Del mismo modo existe Action<...> que hace lo mismo pero sin un tipo de retorno.

No hay nada de mágico en Func<...> - es simplemente una forma más sencilla de expresar delegados, mientras que a: usando genéricos (útiles para LINQ), ob: sin necesidad de que usted busque cuáles son los argumentos; si el tipo de delegado es algo oscuro (PipeStreamImpersonationWorker por ejemplo) puede ser difícil saber lo que se necesita; si eso se expresó como el Action comparable, estaría claro que no requiere parámetros y devuelve void.

1

Func < ..., T> es delegado. donde T es tipo de retorno, y todos los demás parámetros de entrada.

7

Func<int> (por ejemplo) es un tipo (en la forma en que string es un tipo). Entonces lo usa para declarar variables, campos, parámetros, etc.

representa un cálculo que se puede hacer siempre que lo pide una respuesta:

Func<int> f =() => DateTime.Now.Second; 

// elsewhere... 

Console.WriteLine(f()); 

Nota cómo se le puede llamar como un método.Hay muchas versiones sobrecargadas de Func para admitir diferentes números de parámetros. El último argumento de tipo es el tipo de retorno.

Func<int, string> quoteInt = n => "\"" + n + "\""; 

Console.WriteLine(quoteInt(3)); 

Func es un tipo de delegado. Puede declarar el suyo, pero es más fácil de usar Func. Si desea devolver void, use Action en lugar de Func. Solo necesita declarar delegados personalizados si necesita los parámetros out o ref.

Al asignar un lambda a Func, puede consultar las variables locales. Esto es extremadamente poderoso; significa que un Func es más que solo código; tiene datos. Por lo tanto, es como un objeto con un único método (que técnicamente es: el método se llama Invoke y el compilador llama implícitamente a ese método cuando llama a un delegado).

La sintaxis () => se puede colocar antes de cualquier expresión para decir "no hagas esto ahora, espera hasta más tarde". Le permite inicializar a un delegado capturando el cálculo retrasado. Y luego, la sintaxis () se puede ubicar después del delegado para activar realmente el cálculo. Por lo tanto, el sufijo () es tipo de opuesto al prefijo () =>.

+0

+1 para una clara explicación. –

10

Esto podría ayudar. Supongamos que cada vez que vea Func<int, string> se piensa a sí mismo:

interface IFuncIntString 
{ 
    string Invoke(int x); 
} 

Es decir, el delegado es un objeto que implementa esta interfaz. Tiene un único método llamado Invoke que toma un int y devuelve una cadena.

Ahora agregue a eso la función que puede omitir la "Invocación" en una llamada, y usted tiene un delegado.

+0

Así es como me gusta pensar en los delegados. – kenny

+2

La mejor manera de explicarlo a un programador de Java;) – juharr

1

Si alguna vez ha usado el operador => en C#, y probablemente lo haya hecho, ya ha utilizado Funcs. Simplemente no los ha declarado explícitamente.

Por lo tanto, si se escribe una declaración como

var peopleWhoLikeBlue = people.Where(person => person.FavoriteColor == "Blue"); 

estás pasando un Func<Person, bool> en el método where().

Si quieres ser prolijo, puede volver a escribir esa declaración como esta:

Func<Person, bool> favoriteColorIsBlue = person => person.FavoriteColor == "Blue"; 
var peopleWhoLikeBlue = people.Where(favoriteColorIsBlue); 

y obtendrá el mismo resultado.

Cuestiones relacionadas