2009-06-09 17 views
14

Intento entender por qué un método BeginInvoke no aceptará un método anónimo.Métodos y delegados anónimos

void bgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e) 
{ 
    if (InvokeRequired) 
    { 
     //Won't compile 
     BeginInvoke(delegate(object sender, ProgressChangedEventArgs e) 
     { bgWorker_ProgressChanged(sender, e); }); 
    } 

    progressBar1.Increment(e.ProgressPercentage); 
} 

Me dice 'no se puede convertir de 'método anónimo' a 'System.Delegate' mientras que cuando eché el método anónimo a un delegado que funciona?

BeginInvoke((progressDelegate)delegate { bgWorker_ProgressChanged(sender, e); }); 
+1

un vistazo a esta pregunta, también: http://stackoverflow.com/questions/253138/anonymous-method-in-invoke-call – tanascius

Respuesta

7

La clase de delegado es la clase base para los tipos de delegado. Sin embargo, solo el sistema y los compiladores pueden derivar explícitamente de la clase Delegate o de la clase MulticastDelegate. Tampoco es permisible derivar un nuevo tipo de un tipo de delegado. La clase de delegado no se considera un tipo de delegado; es una clase utilizada para derivar tipos de delegados. Fuente - MSDN

De ahí la necesidad de la conversión explícita a un tipo derivada de delegado. Encontrarías este error de compilación en particular cuando pasas un método anónimo para un parámetro de tipo System.Delegate; afortunadamente, este es un escenario raro. Eso es demasiada flexibilidad.

delegate void MyDelegate(); 

    static void DoSomething_Flexible(Delegate d) 
    { d.DynamicInvoke();  } 
    static void DoSomething_Usable(MyDelegate d) 
    { d();  } 
    static void Main(string[] args) 
    { 
    // requires explicit cast else compile error Error "Cannot convert anonymous method to type 'System.Delegate' because it is not a delegate type  
    DoSomething_Flexible((MyDelegate) delegate { Console.WriteLine("Flexible is here!"); }); 

    // Parameter Type is a .NET Delegate, no explicit cast needed here. 
    DoSomething_Usable(delegate { Console.WriteLine("Usable is here!"); }); 
    } 

Más sobre esto en this page by Ian Griffith. (Ver los párrafos después de la cabecera Notas)

+0

Buena respuesta, pero no estoy seguro de que describiría SomeControl.BeginInvoke (método Delegate, param object [] args) como * rare *. –

+0

@PeterWone - :). Sugiero usar una instancia de BackgroundWorker para manejar la afinidad del subproceso UI. No puede hacer nada con los métodos existentes de terceros escritos de esta manera; deberá marcar con un pequeño molde (Acción). – Gishu

16

Es necesario indicar al compilador lo tipo de delegado para crear, ya que Invoke (etc) acaba de tomar Delegate (en lugar de algo más específico).

Para aplicar a la mayor audiencia, MethodInvoker es un práctico tipo de delegado

BeginInvoke((MethodInvoker) delegate(...) {...}); 

Sin embargo ... BackgroundWorker.ProgressChanged incendios en el hilo de interfaz de usuario automáticamente - por lo que incluso no necesita esto.

5

La mayoría de las veces se trata de un delegado sin parámetros o un predicado en estos casos. La forma más fácil de ordenar esto es enviar su método anónimo directamente a Action o Predicate respectivamente; simplemente no necesita crear un tipo de delegado personalizado para cosas simples como esa.

Por lo que usted tiene algo así como

BeginInvoke((Action)delegate(){YourCode.DoSomething();}); 

o

BeginInvoke((Predicate)delegate(object yourParameter){return YourCode.IsTheParameterSomething(yourParameter)}); 

HTH

Cuestiones relacionadas