Dispatcher.BeginInvoke: no se puede convertir lambda a System.Delegate

81

Estoy intentando llamar System.Windows.Threading.Dispatcher.BeginInvoke. La firma del método es esta:

BeginInvoke(Delegate method, params object[] args)

Estoy intentando pasarle un Lambda en lugar de tener que crear un Delegado.

_dispatcher.BeginInvoke((sender) => { DoSomething(); }, new object[] { this } );

Me está dando un error de compilación diciendo que yo

no se puede convertir el lambda a System.Delegate.

La firma del delegado toma un objeto como parámetro y devuelve vacío. Mi lambda coincide con esto, pero no funciona. ¿Qué me estoy perdiendo?

Miqueas
fuente

Respuestas:

70

Dado que el método toma un System.Delegate , debe darle un tipo específico de delegado, declarado como tal. Esto se puede hacer a través de un reparto o una creación del delegado especificado a través de un nuevo DelegateType de la siguiente manera:

_dispatcher.BeginInvoke(
     new Action<MyClass>((sender) => { DoSomething(); }),
     new object[] { this } 
  );

Además, como señala SLaks , Dispatcher.BeginInvoke toma una matriz params, por lo que puede escribir:

_dispatcher.BeginInvoke(
     new Action<MyClass>((sender) => { DoSomething(); }),
     this
  );

O, si DoSomething es un método en este objeto en sí:

_dispatcher.BeginInvoke(new Action(this.DoSomething));
Reed Copsey
fuente
3
Pero no (x) => {Hacer Algo (); } ¿coincide con la firma del delegado? Pensé que eso era todo lo que debería tener para especificar.
Miqueas
@Micah: System.Delegate no tiene firma, es simplemente "cualquier delegado". Debe proporcionarle un tipo de delegado con una firma. que coincida con su uso.
Reed Copsey
@Reed Pero si en lugar de MyMethod (Action action) (y Action es un delegado) puedo llamar a MyMethod (() => {DoSomething ();}); ¿Por qué no puedo hacer lo mismo con BeginInvoke?
Miqueas
15
@Micah: En realidad, no hay una firma para el delegado, que es lo que causa el problema. Invokey BeginInvoketomar un Delegateobjeto genérico , que puede representar un método de cualquier firma. En circunstancias normales (donde un delegado está fuertemente tipado a una firma particular), el compilador puede inferir el tipo de delegado específico. Es por eso que puede salirse con la suya omitiendo el tipo de delegado en otros escenarios. Sin embargo, puesto que no es ningún tipo de delegado real ya que el compilador no tiene una base razonable (o, en realidad, incluso unos medios ) a utilizar para seleccionar un tipo de delegado.
Adam Robinson
2
@Micah: Porque BeginInvoke no se declara como BeginInvoke (Action ..), sino como BeginInvoke (System.Delegate, ..) Esto le permite usar CUALQUIER tipo de delegado, pero debe especificarlo explícitamente.
Reed Copsey
73

Corta:

_dispatcher.BeginInvoke((Action)(() => DoSomething()));
Erwin Mayer
fuente
8
Aún más breve: no creo que necesite las llaves {} y el punto y coma alrededor de la expresión.
sp3ctum
3
Ni siquiera necesitas (), así que puede ser_dispatcher.BeginInvoke((Action)(DoSomething));
mycroes
9

Uso de Lambda en línea ...

Dispatcher.BeginInvoke((Action)(()=>{
  //Write Code Here
}));
JWP
fuente
7

Si hace referencia a System.Windows.Presentation.dll desde su proyecto y lo agrega, using System.Windows.Threadingentonces puede acceder a un método de extensión que le permite usar la sintaxis lambda.

using System.Windows.Threading;

...

Dispatcher.BeginInvoke(() =>
{
});
logicnet.dk
fuente
No puedo conseguir que esto funcione. ¿Podrías entrar un poco más en detalles?
Tim Pohlmann
Agregué un ejemplo simple. Recuerde hacer referencia a System.Windows.Presentation.dll
logicnet.dk
Eso es exactamente lo que yo, pero ahora funciona ... raro. Quizás hice algo mal la última vez.
Tim Pohlmann
2

Creamos métodos de extensión para esto. P.ej

public static void BeginInvoke(this Control control, Action action)
    => control.BeginInvoke(action);

Ahora podemos decir que es desde dentro de un formulario: this.BeginInvoke(() => { ... }).

Shaun Luttin
fuente