2009-06-10 41 views
33

No puedo ser el único que se cansa de definir y nombrar a un delegado para una sola llamada a algo que requiere un delegado. Por ejemplo, quería llamar .Refresh() en una forma de posiblemente otros hilos, así que escribí este código:delegados anónimos en C#

private void RefreshForm() 
{ 
    if (InvokeRequired) 
     Invoke(new InvokeDelegate(Refresh)); 
    else 
     Refresh(); 
} 

Ni siquiera estoy seguro de que he a, acabo de leer lo suficiente como para tener miedo de que no funcionará en una etapa posterior.
InvokeDelegate se declara realmente en otro archivo, pero ¿necesito Realmente necesito un delegado completo dedicado solo para esto? ¿no hay delegados genéricos en absoluto?
Quiero decir, por ejemplo, hay una clase Pen, pero también hay Bolígrafos. pluma de elección por lo que no tiene que volver a hacer la secuencia completa. No es lo mismo, pero espero que entiendas lo que quiero decir.

+1

No hay "delegados anónimos" en C#. Hay delegados (como lo que estás usando) y métodos anónimos (a los que solo se puede acceder a través de un delegado). – Lucas

+3

Supongo que como la especificación de C# usa el término "método anónimo" sería la forma correcta. Sin embargo, muchas personas utilizan este término para referirse a un delegado instanciado con un método anónimo como parámetro. Por lo tanto, significan lo mismo, pero el contexto en el que alguien podría usar un término sobre otro depende a menudo de si hay una asignación de delegado o si el método anónimo se transfiere directamente a otro método. Doy la bienvenida a cualquier argumento en contra. –

Respuesta

52

Sí. En .NET 3.5 puede usar los delegados Func y Action. Los delegados de Func devuelven un valor, mientras que los delegados de Acción devuelven el vacío. Esto es lo que los nombres de los tipos se vería así:

System.Func<TReturn> // (no arg, with return value) 
System.Func<T, TReturn> // (1 arg, with return value) 
System.Func<T1, T2, TReturn> // (2 arg, with return value) 
System.Func<T1, T2, T3, TReturn> // (3 arg, with return value) 
System.Func<T1, T2, T3, T4, TReturn> // (4 arg, with return value) 

System.Action // (no arg, no return value) 
System.Action<T> // (1 arg, no return value) 
System.Action<T1, T2> // (2 arg, no return value) 
System.Action<T1, T2, T3> // (3 arg, no return value) 
System.Action<T1, T2, T3, T4> // (4 arg, no return value) 

No sé por qué se detuvieron en 4 argumentos cada uno, pero siempre ha sido suficiente para mí.

+2

4 no es una regla concreta, pero más allá de eso, al menos debería considerar la combinación de parámetros de alguna manera. –

+1

Cuando estoy portando un código .NET anterior a 3.5 y veo un delegado, los cambio para Func o Action. – RichardOD

+10

La próxima versión del framework incluirá Func y Action de más de cuatro parámetros. –

4

versión corta:

Invoke((MethodInvoker)delegate { Refresh(); }); 

A continuación, también se puede quitar la comprobación de InvokeRequired; usted puede simplemente llamarlo tal como es. Las obras también si necesita pasar parámetros, así que no hay necesidad de otros delegados específicas de los parámetros (funciona igual de bien con el delegado de Acción sin parámetros también):

private void SetControlText(Control ctl, string text) 
{ 
    Invoke((MethodInvoker)delegate { ctl.Text = text; }); 
} 
+0

¿Por qué crearías un delegado anónimo solo para convertirlo a un tipo de delegado existente? Deberías usar el tipo de delegado directamente. –

+2

@Brian: te refieres a esto: Invoke (new MethodInvoker (delegate {ctl.Text = text;})); ? Por lo que puedo ver, produce exactamente el mismo código IL que mi código anterior, por lo que se trata de un gusto personal, supongo. –

+0

¿Cuál es la diferencia entre MethodInvoker y Action? Además, estoy revisando InvokeRequired porque parece una mejor práctica, por ejemplo, más rápido. – Nefzen

26

Ahí está el delegado de Acción se puede utilizar , así:

private void RefreshForm() 
{ 
    if (InvokeRequired) Invoke(new Action(Refresh)); 
    else Refresh(); 
} 

O, con la sintaxis lambda:

private void RefreshForm() 
{ 
    if (InvokeRequired) Invoke((Action)(() => Refresh())); 
    else Refresh(); 
} 

Finalmente, está la sintaxis delegado anónimo:

private void RefreshForm() 
{ 
    if (InvokeRequired) Invoke((Action)(delegate { Refresh(); })); 
    else Refresh(); 
} 
+2

curiosamente, la segunda y tercera sintaxis no funcionan diciendo que no puede convertirla a System.Delegate porque no es un tipo de delegado. Sin embargo, la acción es definitivamente lo que quiero. – Nefzen

+1

los delegados anónimos no se pueden pasar de esta manera a Invocar porque no son del tipo Delegado. Lo que escribiste aquí ni siquiera compila. –

+1

Heh, eso es lo que recibo por no verificar antes de publicar. Lo arreglaré lo antes posible. –

1

Sí, hay delegados genéricos. Action<T1, T2...> es un delegado genérico que toma algunos parámetros y no devuelve ningún valor, y Func<T1, T2...R> es un delegado genérico que toma algunos parámetros y devuelve un valor.

2

¿Realmente necesito un delegado completo dedicado solo para esto? ¿No hay delegados genéricos en absoluto?

La definición de sus propios delegados realmente puede facilitar la depuración, aunque solo sea porque Intellisense puede indicarle los nombres de sus parámetros. Por ejemplo, se escribe un delegado de la siguiente manera:

public delegate int UpdateDelegate(int userID, string city, string, state, string zip); 

Cuando usted lo utiliza código, .NET le informará de los nombres de los parámetros, delegar nombre, etc, así que hay un montón de contexto adecuado en la definición delegado si no está seguro exactamente cómo se usa algo.

Sin embargo, si no le importa sacrificar Intellisense, ya existe una clase de delegados definined en el espacio de nombres System que puede ser utilizado como delegados ad-hoc:

Func<T> 
Func<T, U> 
Func<T, U, V> 
Func<T, U, V, W> 
Action, Action<T> 
Action<T, U> 
Action<T, U, V> 
Action<T, U, V, W> 

Sólo Action y existen en Action .NET 2.0, pero es bastante fácil declarar una clase de ayuda con los delegados restantes que necesita para este tipo de funciones ad hoc misceláneas.

8

En este caso específico, puede (y debería) simplemente usar MethodInvoker para hacer esto ... es por eso que existe.

if (InvokeRequired) 
    Invoke(new MethodInvoker(Refresh)); 
else 
    Refresh(); 

si estuviera haciendo algo más que podía, su uso como otros han respondido Func < T, ... > o Acción < T, ... > si se ajustan a su caso de uso.

+1

Esta es la mejor solución para .NET 2.0 –