ventajas usar tipo runtimebinderexception runtimebinder puede porque microsoft los invocar funcionan ejemplos delegate delegados delegado csharp como c# delegates action func

c# - tipo - Crear delegados manualmente versus usar delegados Action/Func



porque usar delegate c# (8)

Hoy estaba pensando en declarar esto:

private delegate double ChangeListAction(string param1, int number);

pero por qué no usar esto:

private Func<string, int, double> ChangeListAction;

o si ChangeListAction no tuviera valor de retorno que pudiera usar:

private Action<string,int> ChangeListAction;

Entonces, ¿dónde está la ventaja al declarar un delegado con la palabra clave delegate ?

¿Es por .NET 1.1, y con .NET 2.0 llegó Action<T> y con .NET 3.5 llegó Func<T> ?


Como algunas respuestas mencionan que la victoria es clara, usted nombra el tipo y será más fácil de entender para un usuario de su API. Yo diría que, en la mayoría de los casos, declaro tipos de delegado para sus apis públicas, pero está bastante bien usar Func<?,?> Internamente.

Un gran beneficio de declarar el tipo de delegado que no se menciona en las otras respuestas es que, aparte de dar un nombre al tipo, también se pueden nombrar los parámetros, esto aumentará enormemente la usabilidad.


Como dijo MSDN , Func<> es un Delegate predefinido. Por primera vez, me confundí acerca de esto. Después de lo experimental, mi comprensión fue bastante más clara. Normalmente, en C #, podemos ver

Type como un puntero a Instance .

El mismo concepto se aplica a

Delegate como un puntero al Method

La diferencia entre estas cosas es que los Delegate no poseen el concepto de OOP, por ejemplo, Inheritance . Para aclarar esto, hice lo experimental con

public delegate string CustomDelegate(string a); // Func<> is a delegate itself, BUILD-IN delegate //========== // Short Version Anonymous Function //---------- Func<string, string> fShort = delegate(string a) { return "ttt"; }; // Long Version Anonymous Function //---------- Func<string, string> fLong = a => "ttt"; MyDelegate customDlg; Func<string, string> fAssign; // if we do the thing like this we get the compilation error!! // because fAssign is not the same KIND as customDlg //fAssign = customDlg;

Muchos métodos integrados en el marco (por ejemplo, LINQ) reciben el parámetro de Func<> delegado. Lo que podemos hacer con este método es

Declare el delegado del tipo Func<> y páselo a la función en lugar de Define el delegado personalizado.

Por ejemplo, desde el código anterior agrego más código

string[] strList = { "abc", "abcd", "abcdef" }; strList.Select(fAssign); // is valid //strList.Select(customDlg); // Compilation Error!!


Declarar explícitamente a un delegado puede ayudar con algunas comprobaciones de tipo. El compilador puede asegurarse de que el delegado asignado a la variable se use como ChangeListAction y no de alguna acción aleatoria que resulte ser compatible con la firma.

Sin embargo, el valor real de declarar a su propio delegado es que le da un significado semántico. Una persona que lee el código sabrá lo que el delegado está haciendo por su nombre. Imagínese si tuviera una clase con tres campos int pero, en su lugar, declaró una matriz de tres elementos int. La matriz puede hacer lo mismo pero los nombres de los campos brindan información semántica que es útil para los desarrolladores.

Debe usar delegados Func, Predicado y Acción cuando diseña una biblioteca de propósito general como LINQ. En este caso, los delegados no tienen una semántica predefinida que no sea el hecho de que ejecutarán y actuarán o se usarán como un predicado.

En una nota al margen hay un problema de equilibrio similar con Tuple vs tipo anónimo contra declarar su propia clase. Podrías simplemente pegar todo en una Tupla pero luego las propiedades son solo Item1, Item2 que no dice nada sobre el uso del tipo.


Declare explícitamente al delegado cuando comience a obtener demasiados parámetros en Func / Action; de lo contrario, tendrá que mirar hacia atrás, "¿Qué significa nuevamente el segundo int?"


El advenimiento de la familia de delegados de Action y Func ha hecho que los delegados personalizados sean menos utilizados, pero este último aún encuentra usos. Las ventajas de los delegados personalizados incluyen:

  1. Como han señalado otros, transmite intenciones claramente a diferencia de Action y Func genéricos ( Patrik tiene un muy buen punto sobre nombres de parámetros significativos).

  2. Puede especificar parámetros de ref / out diferencia de los otros dos delegados genéricos. Por ejemplo, puede tener

    public delegate double ChangeListAction(out string p1, ref int p2);

    pero no

    Func<out string, ref int, double> ChangeListAction;

  3. Además, con los delegados personalizados, debe escribir ChangeListAction (me refiero a la definición) solo una vez en algún lugar de su base de códigos, mientras que si no define uno, tendrá que Func<string, int, double> basura en todas partes Func<string, int, double> todas partes. Cambiar la firma será una molestia en este último caso, un mal caso de no estar seco.

  4. Puede tener parámetros opcionales

    public delegate double ChangeListAction(string p1 = "haha", int p2);

    pero no

    Func<string, int, double> ChangeListAction = (p1 = "haha", p2) => (double)p2;

  5. Puede tener la palabra clave params para los parámetros de un método, no así con Action/Func .

    public delegate double ChangeListAction(int p1, params string[] p2);

    pero no

    Func<int, params string[], double> ChangeListAction;

  6. Bueno, si estás realmente fuera de suerte y necesitas parámetros de más de 16 (por el momento) :)

En cuanto a los méritos de Action y Func :

  1. Es rápido y sucio, y lo uso por todas partes. Hace que el código sea corto si el caso de uso es trivial (los delegados personalizados han pasado de moda conmigo).

  2. Más importante aún, su tipo es compatible en todos los dominios. Action y Func son framework definidos, y funcionan perfectamente siempre que los tipos de parámetros coincidan. No puede tener ChangeSomeAction para ChangeListAction . Linq encuentra un gran uso de este aspecto.


He encontrado un caso de uso especial donde solo puedes usar delegar:

public delegate bool WndEnumProc(IntPtr hwnd, IntPtr lParam); [DllImport("User32.dll")] public static extern bool EnumWindows(WndEnumProc lpEnumFunc, IntPtr lParam);

El uso de Func / Action simplemente no funciona: ''Namespace.Class.WndEnumProc'' is a ''field'' but is used like a ''type'' :

public Func<IntPtr, IntPtr, bool> WndEnumProc; [DllImport("User32.dll")] public static extern bool EnumWindows(WndEnumProc lpEnumFunc, IntPtr lParam);

El siguiente código se compila, pero arroja una excepción cuando se ejecuta porque System.Runtime.InteropServices.DllImportAttribute no admite la recopilación de tipos genéricos:

[DllImport("User32.dll")] public static extern bool EnumWindows(Func<IntPtr, IntPtr, bool> lpEnumFunc, IntPtr lParam);

Presento este ejemplo para mostrarle a todos que: a veces delegar es su única opción. Y esta es una respuesta razonable a su pregunta, why not use Action<T>/Func<T> ?


La ventaja es claridad. Al darle al tipo un nombre explícito, es más claro para el lector lo que hace.

También lo ayudará cuando escriba el código. Un error como este:

cannot convert from Func<string, int, double> to Func<string, int, int, double>

es menos útil que uno que dice:

cannot convert from CreateListAction to UpdateListAction

También significa que si tiene dos delegados diferentes, los cuales toman los mismos tipos de parámetros pero conceptualmente hacen dos cosas completamente diferentes, el compilador puede asegurarse de que no pueda usar accidentalmente uno queriendo decir el otro.


Para una respuesta mejor y más elaborada mira @nawfal. Trataré de ser más simplista.

Estás declarando un miembro de una clase, por lo que debes quedarte con el delegado. Usar delegate es más descriptivo y estructural.

Action/Func tipos Action/Func están hechos para pasar, por lo que debe usarlos más como parámetros y variables locales.

Y en realidad, ambos están heredando la clase Delegate . Action y Func son tipos genéricos y simplifican la creación de delegados con diferentes tipos de parámetros. Y la palabra clave delegar realmente crea una clase completamente nueva que hereda del Delegado en una declaración.