Dispatcher.BeginInvoke:无法将Lambda表达式转换为System.Delegate。

85

我正在尝试调用System.Windows.Threading.Dispatcher.BeginInvoke方法。该方法的签名如下:

BeginInvoke(Delegate method, params object[] args)
我试图传递一个Lambda表达式而不是创建一个委托。
_dispatcher.BeginInvoke((sender) => { DoSomething(); }, new object[] { this } );

编译器报错,提示我无法将lambda转换为System.Delegate。

委托的签名需要一个对象作为参数并返回void。我的lambda与此相匹配,但它不起作用。我漏掉了什么?


这个回答解决了你的问题吗?无法将lambda表达式转换为类型'System.Delegate' - StayOnTarget
5个回答

76

更短:

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

8
不需要在表达式周围加上花括号{}和分号。 - sp3ctum
3
你甚至不需要括号,因此可以这样写:_dispatcher.BeginInvoke((Action)(DoSomething)); - mycroes
甚至可以使用_dispatcher.BeginInvoke(DoSomething); - Athanviel

74

由于这个方法需要一个System.Delegate,你需要给它一个特定类型的委托,并声明如下。可以通过转换或通过new DelegateType创建指定的委托来完成:

_dispatcher.BeginInvoke(
     new Action<MyClass>((sender) => { DoSomething(); }),
     new object[] { this } 
  );
此外,正如SLaks所指出的那样,Dispatcher.BeginInvoke 接受一个可变参数数组,因此您可以直接编写以下代码:
_dispatcher.BeginInvoke(
     new Action<MyClass>((sender) => { DoSomething(); }),
     this
  );

或者,如果DoSomething是该对象自身上的一个方法:

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

3
但是 (x) => { DoSomething(); } 不是委托的签名吗?我认为那就是我需要指定的全部内容。 - Micah
@Micah:System.Delegate没有签名 - 它只是“任何委托”。您需要提供一个具有与您的用法匹配的签名的委托类型。 - Reed Copsey
@Reed 但是,如果我可以调用MyMethod(() => { DoSomething(); });(其中Action是一个委托),而不是MyMethod(Action action),为什么我不能对BeginInvoke做同样的事情呢? - Micah
16
@Micah:实际上,对于委托来说是没有签名的,这就是引起问题的原因。InvokeBeginInvoke采用了一个泛型的Delegate对象,它可以表示任何签名的方法。在正常情况下(委托被强类型到特定的签名),编译器可以推断出具体的委托类型。这就是为什么在其他场景中省略委托类型时您能够顺利通过的原因。但是,由于这里实际上是没有委托类型的,编译器没有合理的依据(或者说甚至没有一种手段)来选择一个委托类型。 - Adam Robinson
2
@Micah:因为BeginInvoke没有声明为BeginInvoke(Action ..),而是声明为BeginInvoke(System.Delegate, ..)。这使它可以使用任何委托类型,但必须显式指定。 - Reed Copsey
我很想知道他们为什么这样做!Invoke以一个理智的方式工作:Invoke(()=>{}); 为什么BeginInvoke强制你要这样做?无论如何,我仍然会给所有的DispatcherObjects提供一个舒适的扩展方法,但是,为什么呢? - ASA

10

使用内联 Lambda...

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

7
如果您在项目中引用了System.Windows.Presentation.dll并添加了using System.Windows.Threading,那么您可以访问一个扩展方法,该方法允许您使用lambda语法。
using System.Windows.Threading;

...

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

我无法让它工作。你能详细解释一下吗? - Tim Pohlmann
我已经添加了一个简单的示例。请记得引用 System.Windows.Presentation.dll。 - logicnet.dk
这正是我想要的,但现在它却奇怪地工作了。也许上次我做错了什么。 - Tim Pohlmann

5
我们为此创建扩展方法。例如:
public static void BeginInvoke(this Control control, Action action)
    => control.BeginInvoke(action);

现在我们可以在表单内部调用它:this.BeginInvoke(() => { ... })

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接