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?

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));

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()));

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
}));

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(() =>
{
});

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(() => { ... }).

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.