2008-11-26 12 views
25

Disculpe si esto es básico pero estaba tratando de detectar .Net 3.5.¿Qué tiene de bueno Func <> delegate?

Pregunta: ¿Hay algo bueno sobre Func <> y son 5 sobrecargas? Por lo que parece, aún puedo crear un delgate similar por mi propia cuenta, MyFunc <> con las 5 sobrecargas exactas y aún más.

por ejemplo: public delegate TResult MyFunc<TResult>() y una combinación de varias sobrecargas ...

La idea se le ocurrió cuando estaba tratando de entender Func <> delegados y dio con el siguiente escenario:

Func<int,int> myDelegate = (y) => IsComposite(10); 

Esto implica un delegado con un parámetro de tipo int y un tipo de retorno de tipo int. Hay cinco variaciones (si miras las sobrecargas a través de intellisense). Entonces, ¿supongo que podemos tener un delegado sin tipo de devolución?

¿Estoy justificado al decir que Func <> no es nada genial y solo un ejemplo en el framework .Net que podemos usar y si es necesario, crear delegados personalizados "func <>" para satisfacer nuestras propias necesidades?

Gracias,

Respuesta

12

El Func familia de los delegados (y sus primos de retorno de tipo-menos, Action) no son nada más que cualquier otra cosa que usted encontraría en el marco .NET. Están allí para su reutilización, por lo que no es necesario redefinirlos. Tienen parámetros de tipo para mantener las cosas genéricas. Por ejemplo, un Func < T0, bool> es lo mismo que un System.Predicate < T> delegate. Originalmente fueron diseñados para LINQ.

Debería poder simplemente usar el delegado incorporado Func para cualquier método de devolución de valor que acepte hasta 4 argumentos en lugar de definir su propio delegado para tal fin a menos que desee que el nombre refleje su intención, que es genial

Los casos en que usted absolutamente necesita para definir los tipos de delegado incluyen métodos que aceptan más de 4 argumentos, métodos con cabo, ref, o params parámetros, o firmas de los métodos recursivos (por ejemplo, delegate Foo Foo(Foo f)).

9

Además de respuesta correcta de Marxidad:

  • Vale la pena estar al tanto de la familia relacionada de Func, los delegados Action. Nuevamente, estos son tipos sobrecargados por el número de parámetros de tipo, pero declarados como inválidos.
  • Si desea utilizar Func/Action en un proyecto .NET 2.0 pero con una ruta simple para actualizar más adelante, puede cortar y pegar las declaraciones de mi version comparison page. Si los declara en el espacio de nombre System, podrá actualizar simplemente eliminando las declaraciones más tarde, pero no podrá (fácilmente) compilar el mismo código en .NET 3.5 sin eliminar las declaraciones.
64

La grandeza radica en establecer idioma compartido para una mejor comunicación.

En lugar de definir sus propios tipos de delegados para la misma tarea (explosión delegada), utilice los que proporciona el marco. Cualquiera que lea tu código capta instantáneamente lo que estás tratando de lograr ... minimiza el tiempo para '¿qué está haciendo realmente este código?' Así que en cuanto veo un

  • Acción = algún método que simplemente hace algo y devuelve ninguna salida
  • Comparación = algún método que compara dos objetos del mismo tipo y devuelve un int a indican orden
  • convertidor = transforma Obj a en equivalente Obj B
  • EventHandler = respuesta/manipulador a un evento planteada por algún objeto dado una cierta entrada en la forma de un argumento evento
  • Func = algún método que se lleva a algunos parámetros, calcula algo y devuelve un resultado
  • predicado = evalúan objeto de entrada contra algunos criterios y pase vuelven/error estado como bool

No tengo que cavar más profundo que eso a menos que sea mi área inmediata de preocupación. Entonces, si siente que el delegado que necesita se ajusta a una de estas necesidades, úselo antes de hacer su propio esfuerzo.

Descargo de responsabilidad: Personalmente, me gusta este movimiento de los diseñadores de idiomas.

Contraargumento: A veces la definición de su delegado puede ayudar a comunicar mejor la intención. p.ej. System.Threading.ThreadStart sobre System.Action. Entonces, es una decisión final al final.

+1

hombre .. acaba de conseguir skeeted :) – Gishu

+7

Nah, su respuesta es mejor. Me alegra que Func/Action esté allí, y son * generalmente * suficientes, pero creo que todavía hay momentos en los que vale la pena definir a sus propios delegados. Un buen ejemplo es el predicado: no es estrictamente necesario cuando ya existe Func pero indica intención. –

+0

Del mismo modo, es posible que desee proporcionar un delegado con nombre que * pueda * ser representado como Func (o lo que sea) - llamándolo MatchCounter hace que la intención sea más clara. Es un acto de equilibrio. La ventaja de usar Func, por supuesto, es que no necesita buscar el delegado ... –

7

Dependencias de desacoplamiento y amarres impíos es una cosa singular que lo hace genial. Todo lo demás puede debatirse y afirmarse factible de alguna manera local.

He estado refabricando un sistema un poco más complejo con una lib vieja y pesada y me bloquearon al no poder romper la dependencia del tiempo de compilación, debido a que el delegado nombrado acecha en "el otro lado". Toda la carga y reflexión del ensamblaje no ayudaron: el compilador se negaría a enviar un delegado() {...} al objeto y lo que sea que hagas para pacificarlo fallaría en el otro lado.

La comparación del tipo delegado que es estructural en el tiempo de compilación se vuelve nominal después de eso (cargando, invocando). Eso puede parecer correcto mientras piensas en términos de que "mi querida lib va ​​a ser utilizada para siempre y por todos", pero no se adapta a sistemas incluso un poco más complejos. Las plantillas divertidas <> traen un cierto grado de equivalencia estructural al mundo del tipado nominal. Ese es el aspecto que no puedes lograr al implementar el tuyo.

Ejemplo - conversión:

class Session ( 
    public delegate string CleanBody(); // tying you up and you don't see it :-) 
    public static void Execute(string name, string q, CleanBody body) ... 

a:

public static void Execute(string name, string q, Func<string> body) 

permite que el código completamente independiente a hacer la reflexión invocación como:

Type type = Type.GetType("Bla.Session, FooSessionDll", true); 
MethodInfo methodInfo = type.GetMethod("Execute"); 

Func<string> d = delegate() { .....} // see Ma - no tie-ups :-) 
Object [] params = { "foo", "bar", d}; 
methodInfo.Invoke("Trial Execution :-)", params); 

Código existente no notar la diferencia, el nuevo código no tiene dependencia: paz en la Tierra :-)

1

Una cosa que me gusta de los delegados es que me dejaron declaro métodos dentro de los métodos como tal, esto es útil cuando se desea volver a utilizar una pieza de código, pero sólo se necesita dentro de ese método. Como el propósito aquí es limitar el alcance tanto como sea posible, Func <> es útil.

Por ejemplo:

string FormatName(string pFirstName, string pLastName) { 
    Func<string, string> MakeFirstUpper = (pText) => { 
     return pText.Substring(0,1).ToUpper() + pText.Substring(1); 
    }; 

    return MakeFirstUpper(pFirstName) + " " + MakeFirstUpper(pLastName); 
} 

Es incluso más fácil y más útil cuando se puede utilizar la inferencia, que se puede si se crea una función auxiliar, así:

Func<T, TReturn> Lambda<T, TReturn>(Func<T, TReturn> pFunc) { 
    return pFunc; 
} 

Ahora puede volver a escribir mi función sin la Func <>:

string FormatName(string pFirstName, string pLastName) { 
    var MakeFirstUpper = Lambda((string pText) => { 
     return pText.Substring(0,1).ToUpper() + pText.Substring(1); 
    }); 

    return MakeFirstUpper(pFirstName) + " " + MakeFirstUpper(pLastName); 
} 

Aquí está el código para probar la metho d:

Console.WriteLine(FormatName("luis", "perez")); 
Cuestiones relacionadas