Dispatcher.BeginInvoke: Не вдається перетворити лямбда-значення в System.Delegate


82

Я намагаюся зателефонувати System.Windows.Threading.Dispatcher.BeginInvoke. Підпис методу такий:

BeginInvoke(Delegate method, params object[] args)

Я намагаюся передати йому лямбду замість того, щоб створювати делегата.

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

Це видає мені помилку компілятора, кажучи, що я

не може перетворити лямбду в System.Delegate.

Підпис делегата приймає об'єкт як параметр і повертає void. Моя лямбда відповідає цьому, але це не працює. Чого мені не вистачає?

Відповіді:


71

Оскільки метод приймає System.Delegate , вам потрібно надати йому певний тип делегата, оголошений як такий. Це можна зробити за допомогою приведення або створення вказаного делегата за допомогою нового DelegateType наступним чином:

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

Крім того, як зазначає SLaks , Dispatcher.BeginInvoke бере масив params, тому ви можете просто написати:

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

Або, якщо DoSomething є методом самого цього об’єкта:

_dispatcher.BeginInvoke(new Action(this.DoSomething));

3
Але не (x) => {DoSomething (); } відповідати підпису делегата? Я думав, що це все, що мені потрібно було б уточнити.
Micah

@Micah: System.Delegate не має підпису - це просто "будь-який делегат" взагалі. Вам потрібно надати йому тип делегата зі знаком. що відповідає вашому використанню.
Рід Копсі,

@Reed Але якщо замість MyMethod (Action action) (а Action є делегатом) я можу зателефонувати MyMethod (() => {DoSomething ();}); Чому я не можу зробити те саме для BeginInvoke?
Micah

15
@Micah: Насправді немає підпису для делегата, що є причиною проблеми. Invokeі BeginInvokeвізьмемо загальний Delegateоб’єкт, який може представляти метод будь-якого підпису. За звичайних обставин (де делегат сильно набирається для певного підпису), компілятор може зробити висновок про конкретний тип делегата. Ось чому ви можете уникнути, пропустивши тип делегата в інших сценаріях. Однак, так як немає ніякого фактичного типу делегата тут, компілятор не має розумну підставу (або, на самому ділі, навіть кошти ) використовувати для вибору типу делегата.
Адам Робінсон

2
@Micah: Оскільки BeginInvoke не оголошується як BeginInvoke (Action ..), а швидше BeginInvoke (System.Delegate, ..) Це дозволяє йому використовувати БУДЬ-ЯКИЙ тип делегатів, але ви повинні вказати це явно.
Рід Копсі,

73

Коротше:

_dispatcher.BeginInvoke((Action)(() => DoSomething()));

8
Ще коротше: я не думаю, що вам потрібні фігурні дужки {} та крапка з комою навколо виразу.
sp3ctum

3
Вам навіть не потрібно (), отже, це може бути_dispatcher.BeginInvoke((Action)(DoSomething));
mycroes

9

Використання вбудованої лямбди ...

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

7

Якщо ви посилаєтесь на System.Windows.Presentation.dll у своєму проекті та додаєте, using System.Windows.Threadingто ви можете отримати доступ до методу розширення, який дозволяє використовувати синтаксис лямбда-сигналу.

using System.Windows.Threading;

...

Dispatcher.BeginInvoke(() =>
{
});

Я не можу змусити це працювати. Не могли б ви трохи детальніше?
Тім Полман

Я додав простий приклад. Не забувайте посилатися на System.Windows.Presentation.dll
logicnet.dk

Це саме те, що я, але зараз це працює ... дивно. Можливо, минулого разу я щось зробив не так.
Тім Полман

3

Для цього ми створюємо методи розширення. Напр

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

Тепер ми можемо назвати його зсередини форми: this.BeginInvoke(() => { ... }).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.