Invoke 调用中的匿名方法
在我们想要在 Control.Invoke 中匿名调用委托的语法上遇到了一些问题。
我们尝试了多种不同的方法,但都没有效果。
例如:
myControl.Invoke(delegate() { MyMethod(this, new MyEventArgs(someParameter)); });
where someParameter is local to this method
上面将导致编译器错误:
无法将匿名方法转换为“System.Delegate”类型,因为它不是委托类型
Having a bit of trouble with the syntax where we want to call a delegate anonymously within a Control.Invoke.
We have tried a number of different approaches, all to no avail.
For example:
myControl.Invoke(delegate() { MyMethod(this, new MyEventArgs(someParameter)); });
where someParameter is local to this method
The above will result in a compiler error:
Cannot convert anonymous method to type 'System.Delegate' because it is not a delegate type
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
因为
Invoke
/BeginInvoke
接受Delegate
(而不是类型化委托),所以您需要告诉编译器要创建什么类型的委托;MethodInvoker
(2.0) 或Action
(3.5) 是常见的选择(注意它们具有相同的签名); 像这样:如果您需要传入参数,那么“捕获变量”就是这样:(
警告:如果使用捕获异步,则需要小心一点,但是同步 很好 - 即上面的很好)
另一个选择是编写一个扩展方法:
那么:
你当然可以用
BeginInvoke
做同样的事情:如果你不能使用 C# 3.0,你可以这样做与常规实例方法相同,大概在
Form
基类中。Because
Invoke
/BeginInvoke
acceptsDelegate
(rather than a typed delegate), you need to tell the compiler what type of delegate to create ;MethodInvoker
(2.0) orAction
(3.5) are common choices (note they have the same signature); like so:If you need to pass in parameters, then "captured variables" are the way:
(caveat: you need to be a bit cautious if using captures async, but sync is fine - i.e. the above is fine)
Another option is to write an extension method:
then:
You can of course do the same with
BeginInvoke
:If you can't use C# 3.0, you could do the same with a regular instance method, presumably in a
Form
base-class.实际上你不需要使用 delegate 关键字。 只需传递 lambda 作为参数:
Actually you do not need to use delegate keyword. Just pass lambda as parameter:
您需要创建一个委托类型。 匿名方法创建中的关键字“委托”有点误导。 您不是创建匿名委托,而是创建匿名方法。 您创建的方法可以在委托中使用。 像这样:
You need to create a delegate type. The keyword 'delegate' in the anonymous method creation is a bit misleading. You are not creating an anonymous delegate but an anonymous method. The method you created can be used in a delegate. Like this:
为了完整起见,这也可以通过 Action 方法/匿名方法组合来完成:
For the sake of completeness, this can also be accomplished via an Action method/anonymous method combination:
我对其他建议有疑问,因为我有时想从我的方法中返回值。 如果您尝试将 MethodInvoker 与返回值一起使用,它似乎不喜欢它。 所以我使用的解决方案是这样的(很高兴听到一种使这个更简洁的方法 - 我正在使用 c#.net 2.0):
I had problems with the other suggestions because I want to sometimes return values from my methods. If you try to use MethodInvoker with return values it doesn't seem to like it. So the solution I use is like this (very happy to hear a way to make this more succinct - I'm using c#.net 2.0):
我喜欢使用 Action 代替 MethodInvoker,它更短并且看起来更干净。
例如。
I like to use Action in place of MethodInvoker, it is shorter and looks cleaner.
Eg.
我一直不明白为什么这会对编译器产生影响,但这已经足够了。
奖励:添加一些错误处理,因为如果您从后台线程使用
Control.Invoke
,您可能会更新控件的文本/进度/启用状态,并且不关心是否该控件已被处理。I never understood why this makes a difference for the compiler, but this is sufficient.
Bonus: add some error handling, because it is likely that, if you are using
Control.Invoke
from a background thread you are updating the text / progress / enabled state of a control and don't care if the control is already disposed.我需要它来显示来自单独线程的模式对话框,但实际上我也可以从中获取返回值。 Vokinneberg 的答案让我走上了正轨,但我仍然需要更多东西。
我想出的最终解决方案是将其添加为
MethodInvoker
的函数版本:现在,如果我有一个像这样的函数,它显示一个模式对话框并从中返回数据
...。 ..可以从不同的线程中这样调用:
现在,一切正常:在主窗体上调用该函数,对话框显示为主窗体的模式对话框,并且对话框中的值返回到另一个线程,它可以继续处理。
那里仍然有一些丑陋的强制转换,因为
Control.Invoke
碰巧返回一个对象,但它仍然可以用于任何函数,只要不涉及输出参数等高级内容。如果我使用泛型,可能可以使这个更清晰,作为
Form
上的扩展方法或其他东西,在内部进行强制转换。 但现在,这样就可以了。I needed this to show a modal dialog from a separate thread, but in a way that I could actually get a return value from it, too. Vokinneberg's answer put me on the right track, but I still needed something more.
The final solution I came up with was to add this, as function-version of
MethodInvoker
:Now, if I have a function like this, which shows a modal dialog and returns data from it...
...it can be called like this from the different thread:
Now, everything works: the function is invoked on the main form, the dialog is shown as modal dialog of the main form, and the value from the dialog is returned to the other thread, which can continue its processing.
There's still some ugly casts in there, because
Control.Invoke
happens to return an Object, but still, it can be used for any function, as long as there are no advanced things like output-parameters involved.It's probably possible to make this cleaner, as extension method on
Form
or something, that does the casts internally, if I work with generics. But for now, this'll do.