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

xyz*_*xyz 120 c# lambda delegates c#-3.0

采取方法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
Run Code Online (Sandbox Code Playgroud)

但这很好用:

string str = "woop";
Invoke((Action)(() => this.Text = str));
Run Code Online (Sandbox Code Playgroud)

当方法需要普通代表时?

Jon*_*eet 122

lambda表达式可以转换为委托类型或表达式树 - 但它必须知道哪个委托类型.只知道签名是不够的.例如,假设我有:

public delegate void Action1();
public delegate void Action2();

...

Delegate x = () => Console.WriteLine("hi");
Run Code Online (Sandbox Code Playgroud)

您期望所提及的对象的具体类型x是什么?是的,编译器可以生成具有适当签名的新委托类型,但这很少有用,并且最终减少了错误检查的机会.

如果您希望通过最简单的方法轻松调用Control.Invoke,Action请向Control添加扩展方法:

public static void Invoke(this Control control, Action action)
{
    control.Invoke((Delegate) action);
}
Run Code Online (Sandbox Code Playgroud)

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

小智 33

厌倦了一遍又一遍地抛弃lambda?

public sealed class Lambda<T>
{
    public static Func<T, T> Cast = x => x;
}

public class Example
{
    public void Run()
    {
        // Declare
        var c = Lambda<Func<int, string>>.Cast;
        // Use
        var f1 = c(x => x.ToString());
        var f2 = c(x => "Hello!");
        var f3 = c(x => (x + x).ToString());
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这是对泛型的美妙使用. (3认同)
  • 我不得不承认,这需要我一段时间来弄清楚它为什么会起作用.辉煌.太糟糕了我现在没用它. (2认同)
  • 您能解释一下这个的用法吗?这对我来说很难理解吗?多谢。 (2认同)

Pet*_*one 12

人们得到这个的时间只有十分之九,因为他们正试图编组到UI线程上.这是懒惰的方式:

static void UI(Action action) 
{ 
  System.Windows.Threading.Dispatcher.CurrentDispatcher.BeginInvoke(action); 
}
Run Code Online (Sandbox Code Playgroud)

现在它被打字了,问题消失了(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);        
  });
}
Run Code Online (Sandbox Code Playgroud)

对于奖励积分,这是另一个提示.您不会为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
}
Run Code Online (Sandbox Code Playgroud)

最后的提示是因为事情会变得纠结:WaitHandles会阻止线程.这是他们应该做的.如果您在停止时尝试编组UI线程,您的应用程序将挂起.在这种情况下(a)一些严重的重构是有序的,并且(b)作为临时黑客你可以这样等待:

  bool wait = true;
  ThreadPool.QueueUserWorkItem ((state) =>
  {
    //do asynch stuff        
    wait = false;
  });
  while (wait) Thread.Sleep(100);
Run Code Online (Sandbox Code Playgroud)

  • 我觉得很有意思的是,人们只是因为他们个人并不觉得有吸引力而拒绝回答.如果这是*错*并且你知道这一点,那就说出它有什么问题.如果你不能这样做,那么你没有进行downvote的基础.如果它是史诗般的错误,那么请说"Baloney.请参阅[正确答案]"或者"不是推荐的解决方案,请参阅[更好的东西]" (3认同)