delegates - method - ¿Qué tiene de bueno Func<> delegate?
generic delegates in c# (6)
Lo siento si esto es básico, pero estaba tratando de aprender sobre .Net 3.5.
Pregunta: ¿Hay algo bueno sobre Func <> y sobre 5 sobrecargas? Por lo que parece, todavía 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 un conjunto de varias sobrecargas ...
La idea surgió cuando intenté entender a los delegados de Func y acerté 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?
Entonces, ¿estoy justificado al decir que Func <> no es nada grandioso y solo un ejemplo en el framework .Net que podemos usar y, si es necesario, crear delegados "func <>" personalizados para satisfacer nuestras propias necesidades?
Gracias,
Además de la respuesta correcta de Marxidad:
- Vale la pena estar al tanto de la familia relacionada de Func, los delegados de
Action
. Nuevamente, estos son tipos sobrecargados por el número de parámetros de tipo, pero declarados como inválidos. - Si desea usar 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 página de comparación de versiones . Si los declaras en el espacio de nombres del
System
, podrás actualizarlos simplemente eliminando las declaraciones más tarde, pero luego no podrás (fácilmente) compilar el mismo código en .NET 3.5 sin eliminar las declaraciones.
Aunque es un hilo antiguo, tuve que añadir que func <> y action <> también nos ayudan a usar la varianza de covarianza y contra.
La familia de delegados de Func
(y sus primos sin retorno, Action
) no son mayores que cualquier otra cosa que encontrarías en .NET Framework. 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 delegado System.Predicate <T>. Originalmente fueron diseñados para LINQ.
Debería poder usar el delegado integrado de 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, lo cual es genial.
Los casos en los que sería absolutamente necesario definir sus tipos de delegados incluyen métodos que aceptan más de 4 argumentos, métodos con parámetros out , ref o params , o firmas de métodos recursivos (por ejemplo, delegate Foo Foo(Foo f)
).
La grandeza radica en establecer un lenguaje 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?'' Entonces, tan pronto como veo un
- Acción = algún método que solo hace algo y no devuelve ningún resultado
- Comparación = algún método que compara dos objetos del mismo tipo y devuelve un int para indicar el orden
- Convertidor = transforma Obj A en Obj B equivalente
- EventHandler = respuesta / manejador a un evento generado por algún objeto con alguna entrada en forma de un argumento de evento
- Func = algún método que toma algunos parámetros, calcula algo y devuelve un resultado
- Predicado = evalúa el objeto de entrada según algunos criterios y devuelve el estado de aprobación / falla 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.
Argumento contrario : a veces la definición de su delegado puede ayudar a comunicar mejor el intento. por ejemplo System.Threading.ThreadStart
over System.Action
. Entonces, es una decisión final al final.
Una cosa que me gusta de los delegados es que me permiten declarar métodos dentro de métodos como este, esto es útil cuando quieres reutilizar un fragmento de código pero solo lo necesitas dentro de ese método. Dado que 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 puedes usar la inferencia, lo que puedes hacer si creas una función auxiliar de esta manera:
Func<T, TReturn> Lambda<T, TReturn>(Func<T, TReturn> pFunc) {
return pFunc;
}
Ahora puedo reescribir mi función sin 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 el método:
Console.WriteLine(FormatName("luis", "perez"));
Desacoplamiento de dependencias 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 han bloqueado el 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 de delegado que es estructural en el momento de la compilación se vuelve nominal después de eso (carga, invocación). 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 <> devuelven 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 un código completamente independiente haga una invocación de reflexió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);
El código existente no nota la diferencia, el nuevo código no tiene dependencia, paz en la Tierra :-)