当前位置:  开发笔记 > 编程语言 > 正文

为什么必须在作为普通的Delegate参数提供时转换lambda表达式

如何解决《为什么必须在作为普通的Delegate参数提供时转换lambda表达式》经验,为你挑选了3个好方法。

采取方法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));

当方法需要普通代表时?



1> Jon Skeet..:

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调用Begin/Invoke的情况下,您当然不关心委托类型是否是自动生成的,我们只想进行调用.在什么情况下接受Delegate(基类型)的方法关心具体类型是什么?另外,扩展方法的目的是什么?它没有使任何事情变得更容易.
啊! 我添加了扩展方法并尝试了`Invoke(()=> DoStuff)`但仍然出错.问题是我使用了隐含的'this'.要使它在Control成员中工作,您必须明确:`this.Invoke(()=> DoStuff)`.
对于阅读此内容的其他人,我认为[C#:自动化InvokeRequired代码模式](http://stackoverflow.com/a/2367763/209259)的问题和答案非常有用.

2> 小智..:

厌倦了一遍又一遍地抛弃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());
    }
}


这是对泛型的美妙使用.
我不得不承认,这需要我一段时间来弄清楚它为什么会起作用.辉煌.太糟糕了我现在没用它.

3> Peter Wone..:

人们得到这个的时间只有十分之九,因为他们正试图编组到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);


我觉得很有意思的是,人们只是因为他们个人并不觉得有吸引力而拒绝回答.如果这是*错*并且你知道这一点,那就说出它有什么问题.如果你不能这样做,那么你没有进行downvote的基础.如果它是史诗般的错误,那么请说"Baloney.请参阅[正确答案]"或者"不是推荐的解决方案,请参阅[更好的东西]"
推荐阅读
360691894_8a5c48
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有