Dispatcher.BeginInvoke: nie można przekonwertować lambda na System.Delegate

82

Próbuję zadzwonić System.Windows.Threading.Dispatcher.BeginInvoke. Podpis metody jest następujący:

BeginInvoke(Delegate method, params object[] args)

Próbuję przekazać mu Lambdę zamiast tworzyć delegata.

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

Daje mi błąd kompilatora mówiący, że ja

nie można przekonwertować lambdy na System.Delegate.

Podpis delegata przyjmuje obiekt jako parametr i zwraca void. Moja lambda pasuje do tego, ale nie działa. czego mi brakuje?

Micheasza
źródło

Odpowiedzi:

71

Ponieważ metoda przyjmuje System.Delegate , musisz nadać jej określony typ delegata, zadeklarowany jako taki. Można to zrobić za pomocą rzutowania lub utworzenia określonego delegata za pośrednictwem nowego DelegateType w następujący sposób:

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

Ponadto, jak wskazuje SLaks , Dispatcher.BeginInvoke pobiera tablicę params, więc możesz po prostu napisać:

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

Lub, jeśli DoSomething jest metodą samego tego obiektu:

_dispatcher.BeginInvoke(new Action(this.DoSomething));
Reed Copsey
źródło
3
Ale czy (x) => {DoSomething (); } zgadza się z podpisem pełnomocnika? Pomyślałem, że to wszystko, co powinienem określić.
Micah
@Micah: System.Delegate nie ma podpisu - to po prostu „dowolny delegat”. Musisz nadać mu typ delegata z sig. który pasuje do Twojego zastosowania.
Reed Copsey,
@Reed Ale jeśli zamiast MyMethod (akcja Action) (a Action jest delegatem) mogę wywołać MyMethod (() => {DoSomething ();}); Dlaczego nie mogę zrobić tego samego dla BeginInvoke?
Micah,
15
@Micah: Właściwie nie ma podpisu dla delegata, co jest przyczyną problemu. Invokei BeginInvokeweź ogólny Delegateobiekt, który może reprezentować metodę dowolnego podpisu. W normalnych okolicznościach (gdy delegat jest silnie wpisany do określonego podpisu), kompilator może wywnioskować określony typ delegata. Dlatego możesz pominąć typ delegata w innych scenariuszach. Jednak, ponieważ nie ma żadnego rzeczywistego typ delegata tutaj, kompilator nie ma wystarczających podstaw (lub, naprawdę, nawet środki ), aby użyć, aby wybrać typ delegata.
Adam Robinson,
2
@Micah: Ponieważ BeginInvoke nie jest zadeklarowana jako BeginInvoke (Action ..), ale raczej BeginInvoke (System.Delegate, ..) Pozwala to na użycie DOWOLNEGO typu delegata, ale należy go jawnie określić.
Reed Copsey,
73

Krótszy:

_dispatcher.BeginInvoke((Action)(() => DoSomething()));
Erwin Mayer
źródło
8
Jeszcze krócej: myślę, że nie potrzebujesz nawiasów klamrowych {} i średnika wokół wyrażenia.
sp3ctum
3
Nie potrzebujesz nawet (), więc może być_dispatcher.BeginInvoke((Action)(DoSomething));
mykroes
9

Korzystanie z wbudowanej sondy Lambda ...

Dispatcher.BeginInvoke((Action)(()=>{
  //Write Code Here
}));
JWP
źródło
7

Jeśli odwołujesz się do System.Windows.Presentation.dll z projektu i dodajesz using System.Windows.Threading, możesz uzyskać dostęp do metody rozszerzenia, która umożliwia użycie składni lambda.

using System.Windows.Threading;

...

Dispatcher.BeginInvoke(() =>
{
});
logicnet.dk
źródło
Nie mogę zmusić tego do pracy. Czy mógłbyś podać więcej szczegółów?
Tim Pohlmann
Dodałem prosty przykład. Pamiętaj, aby odwołać się do System.Windows.Presentation.dll
logicnet.dk
To jest dokładnie to, co ja, ale teraz działa ... dziwnie. Może ostatnio zrobiłem coś złego.
Tim Pohlmann
3

W tym celu tworzymy metody rozszerzające. Na przykład

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

Teraz możemy nazwać go od wewnątrz postaci: this.BeginInvoke(() => { ... }).

Shaun Luttin
źródło