Método anónimo en Invoke call


Tenemos un poco de problemas con la sintaxis donde queremos llamar a un delegado anónimamente dentro de un Control.Invocar.

Hemos intentado una serie de enfoques diferentes, todos en vano.

Por ejemplo:

myControl.Invoke(delegate() { MyMethod(this, new MyEventArgs(someParameter)); }); 

Donde someParameter es local a este método

Lo anterior resultará en un error del compilador:

No se puede convertir el método anónimo al tipo 'System.Delegate ' porque no es un tipo de delegado

Author: Patrick Hofman, 2008-10-31

7 answers

Porque Invoke/BeginInvoke acepta Delegate (en lugar de un delegado escrito), necesita decirle al compilador qué tipo de delegado crear; MethodInvoker (2.0) o Action (3.5) son opciones comunes (tenga en cuenta que tienen la misma firma); así:

control.Invoke((MethodInvoker) delegate {this.Text = "Hi";});

Si necesita pasar parámetros, entonces "variables capturadas" son la forma:

string message = "Hi";
control.Invoke((MethodInvoker) delegate {this.Text = message;});

(advertencia: debe ser un poco cauteloso si usa capturas async , pero sync está bien, es decir, lo anterior está bien)

Otro la opción es escribir un método de extensión:

public static void Invoke(this Control control, Action action)
{
    control.Invoke((Delegate)action);
}

Entonces:

this.Invoke(delegate { this.Text = "hi"; });
// or since we are using C# 3.0
this.Invoke(() => { this.Text = "hi"; });

Por supuesto, puedes hacer lo mismo con BeginInvoke:

public static void BeginInvoke(this Control control, Action action)
{
    control.BeginInvoke((Delegate)action);
}

Si no puede usar C# 3.0, podría hacer lo mismo con un método de instancia regular, presumiblemente en una clase base Form.

 205
Author: Marc Gravell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-06-04 10:46:05

En realidad no es necesario utilizar la palabra clave delegate. Simplemente pasa lambda como parámetro:

control.Invoke((MethodInvoker)(() => {this.Text = "Hi"; }));
 42
Author: Vokinneberg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-02-24 23:48:57
myControl.Invoke(new MethodInvoker(delegate() {...}))
 13
Author: François,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-12-07 19:04:06

Necesita crear un tipo de delegado. La palabra clave 'delegate' en la creación del método anónimo es un poco engañosa. No está creando un delegado anónimo, sino un método anónimo. El método que ha creado se puede utilizar en un delegado. Así:

myControl.Invoke(new MethodInvoker(delegate() { (MyMethod(this, new MyEventArgs(someParameter)); }));
 13
Author: Jelon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-02-24 23:48:41

En aras de la integridad, esto también se puede lograr a través de una combinación de método de acción/método anónimo:

//Process is a method, invoked as a method group
Dispatcher.Current.BeginInvoke((Action) Process);
//or use an anonymous method
Dispatcher.Current.BeginInvoke((Action)delegate => {
  SomeFunc();
  SomeOtherFunc();
});
 7
Author: mhamrah,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-12-20 22:16:32

Tuve problemas con las otras sugerencias porque a veces quiero devolver valores de mis métodos. Si intenta usar MethodInvoker con valores devueltos, no parece gustarle. Así que la solución que uso es así (muy feliz de escuchar una manera de hacer esto más sucinto - estoy usando c#.net 2.0):

    // Create delegates for the different return types needed.
    private delegate void VoidDelegate();
    private delegate Boolean ReturnBooleanDelegate();
    private delegate Hashtable ReturnHashtableDelegate();

    // Now use the delegates and the delegate() keyword to create 
    // an anonymous method as required

    // Here a case where there's no value returned:
    public void SetTitle(string title)
    {
        myWindow.Invoke(new VoidDelegate(delegate()
        {
            myWindow.Text = title;
        }));
    }

    // Here's an example of a value being returned
    public Hashtable CurrentlyLoadedDocs()
    {
        return (Hashtable)myWindow.Invoke(new ReturnHashtableDelegate(delegate()
        {
            return myWindow.CurrentlyLoadedDocs;
        }));
    }
 5
Author: Rory,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-12 22:22:50

Nunca entendí por qué esto hace una diferencia para el compilador, pero esto es suficiente.

public static class ControlExtensions
{
    public static void Invoke(this Control control, Action action)
    {
        control.Invoke(action);
    }
}

Bonus: añade algo de manejo de errores, porque es probable que, si estás usando Control.Invoke desde un hilo de fondo, estés actualizando el estado de texto / progreso / habilitado de un control y no te importe si el control ya está dispuesto.

public static class ControlExtensions
{
    public static void Invoke(this Control control, Action action)
    {
        try
        {
            if (!control.IsDisposed) control.Invoke(action);
        }
        catch (ObjectDisposedException) { }
    }
}
 0
Author: Jürgen Steinblock,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-12 09:23:17