采取方法System.Windows.Forms.Control.Invoke(Delegate方法)
为什么会出现编译时错误:
string str = "woop"; Invoke(() => this.Text = str); // Error: Cannot convert lambda expression to type 'System.Delegate' // because it is not a delegate type
但这很好用:
string str = "woop"; Invoke((Action)(() => this.Text = str));
当方法需要普通代表时?
lambda表达式可以转换为委托类型或表达式树 - 但它必须知道哪个委托类型.只知道签名是不够的.例如,假设我有:
public delegate void Action1(); public delegate void Action2(); ... Delegate x = () => Console.WriteLine("hi");
您期望所提及的对象的具体类型x
是什么?是的,编译器可以生成具有适当签名的新委托类型,但这很少有用,并且最终减少了错误检查的机会.
如果您希望通过最简单的方法轻松调用Control.Invoke
,Action
请向Control添加扩展方法:
public static void Invoke(this Control control, Action action) { control.Invoke((Delegate) action); }
厌倦了一遍又一遍地抛弃lambda?
public sealed class Lambda{ public static Func Cast = x => x; } public class Example { public void Run() { // Declare var c = Lambda >.Cast; // Use var f1 = c(x => x.ToString()); var f2 = c(x => "Hello!"); var f3 = c(x => (x + x).ToString()); } }
人们得到这个的时间只有十分之九,因为他们正试图编组到UI线程上.这是懒惰的方式:
static void UI(Action action) { System.Windows.Threading.Dispatcher.CurrentDispatcher.BeginInvoke(action); }
现在它被打字了,问题消失了(qv Skeet's anwer),我们有这个非常简洁的语法:
int foo = 5; public void SomeMethod() { var bar = "a string"; UI(() => { //lifting is marvellous, anything in scope where the lambda //expression is defined is available to the asynch code someTextBlock.Text = string.Format("{0} = {1}", foo, bar); }); }
对于奖励积分,这是另一个提示.您不会为UI内容执行此操作,但在需要SomeMethod阻塞直到完成(例如请求/响应I/O,等待响应)的情况下,请使用WaitHandle(qv msdn WaitAll,WaitAny,WaitOne).
请注意,AutoResetEvent是WaitHandle派生物.
public void BlockingMethod() { AutoResetEvent are = new AutoResetEvent(false); ThreadPool.QueueUserWorkItem ((state) => { //do asynch stuff are.Set(); }); are.WaitOne(); //don't exit till asynch stuff finishes }
最后的提示是因为事情会变得纠结:WaitHandles会阻止线程.这是他们应该做的.如果您在停止时尝试编组UI线程,您的应用程序将挂起.在这种情况下(a)一些严重的重构是有序的,并且(b)作为临时黑客你可以这样等待:
bool wait = true; ThreadPool.QueueUserWorkItem ((state) => { //do asynch stuff wait = false; }); while (wait) Thread.Sleep(100);