Dispatcher.BeginInvoke: Lambda kann nicht in System.Delegate konvertiert werden

82

Ich versuche anzurufen System.Windows.Threading.Dispatcher.BeginInvoke. Die Signatur der Methode lautet:

BeginInvoke(Delegate method, params object[] args)

Ich versuche, ihm einen Lambda zu übergeben, anstatt einen Delegierten erstellen zu müssen.

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

Es gibt mir einen Compilerfehler, der besagt, dass ich

Das Lambda kann nicht in ein System.Delegate konvertiert werden.

Die Signatur des Delegaten nimmt ein Objekt als Parameter und gibt void zurück. Mein Lambda passt dazu, aber es funktioniert nicht. Was vermisse ich?

Micah
quelle

Antworten:

71

Da die Methode ein System.Delegate verwendet , müssen Sie ihm einen bestimmten Delegatentyp zuweisen , der als solcher deklariert ist. Dies kann über eine Besetzung oder eine Erstellung des angegebenen Delegaten über den neuen DelegateType wie folgt erfolgen:

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

Wie SLaks hervorhebt , verwendet Dispatcher.BeginInvoke ein params-Array, sodass Sie einfach schreiben können:

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

Oder wenn DoSomething eine Methode für dieses Objekt selbst ist:

_dispatcher.BeginInvoke(new Action(this.DoSomething));
Reed Copsey
quelle
3
Aber nicht (x) => {DoSomething (); } mit der Unterschrift des Delegierten übereinstimmen? Ich dachte, das ist alles, was ich spezifizieren sollte.
Micah
@Micah: System.Delegate hat keine Signatur - es ist überhaupt nur "irgendein Delegat". Sie müssen ihm einen Delegattyp mit einem Sig versehen. das passt zu deiner Nutzung.
Reed Copsey
@Reed Aber wenn anstelle von MyMethod (Action action) (und Action ein Delegat ist) kann ich MyMethod (() => {DoSomething ();}) aufrufen; Warum kann ich für BeginInvoke nicht dasselbe tun?
Micah
15
@Micah: Es gibt tatsächlich keine Signatur für den Delegierten, was das Problem verursacht. Invokeund BeginInvokenehmen Sie ein generisches DelegateObjekt, das eine Methode jeder Signatur darstellen kann. Unter normalen Umständen (wenn ein Delegat stark an eine bestimmte Signatur gebunden ist) kann der Compiler auf den bestimmten Delegatentyp schließen. Aus diesem Grund können Sie den Delegatentyp in anderen Szenarien weglassen. Da es hier jedoch keinen tatsächlichen Delegatentyp gibt, verfügt der Compiler nicht über eine vernünftige Grundlage (oder sogar ein Mittel ), um einen Delegatentyp auszuwählen.
Adam Robinson
2
@Micah: Da BeginInvoke nicht als BeginInvoke (Aktion ..) deklariert ist, sondern als BeginInvoke (System.Delegate, ..). Dies ermöglicht die Verwendung eines beliebigen Delegatentyps, Sie müssen ihn jedoch explizit angeben.
Reed Copsey
73

Kürzere:

_dispatcher.BeginInvoke((Action)(() => DoSomething()));
Erwin Mayer
quelle
8
Noch kürzer: Ich glaube nicht, dass Sie die Klammern {} und das Semikolon um den Ausdruck benötigen.
sp3ctum
3
Sie brauchen nicht einmal (), also kann es sein_dispatcher.BeginInvoke((Action)(DoSomething));
Mycroes
9

Inline Lambda verwenden ...

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

Wenn Sie in Ihrem Projekt auf System.Windows.Presentation.dll verweisen und hinzufügen using System.Windows.Threading, können Sie auf eine Erweiterungsmethode zugreifen, mit der Sie die Lambda-Syntax verwenden können.

using System.Windows.Threading;

...

Dispatcher.BeginInvoke(() =>
{
});
logiknet.dk
quelle
Ich kann das nicht zum Laufen bringen. Könnten Sie etwas näher darauf eingehen?
Tim Pohlmann
Ich habe ein einfaches Beispiel hinzugefügt. Denken Sie daran, auf System.Windows.Presentation.dll
logonet.dk
Genau das habe ich, aber jetzt funktioniert es ... komisch. Vielleicht habe ich beim letzten Mal etwas falsch gemacht.
Tim Pohlmann
3

Hierfür erstellen wir Erweiterungsmethoden. Z.B

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

Jetzt können wir es aus einem Formular heraus aufrufen : this.BeginInvoke(() => { ... }).

Shaun Luttin
quelle