【问题标题】:Anonymous methods and delegates匿名方法和委托
【发布时间】:2010-11-01 09:47:04
【问题描述】:

我试图理解为什么 BeginInvoke 方法不接受匿名方法。

void bgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    if (InvokeRequired)
    {
        //Won't compile
        BeginInvoke(delegate(object sender, ProgressChangedEventArgs e) 
        { bgWorker_ProgressChanged(sender, e); });
    }

    progressBar1.Increment(e.ProgressPercentage);
}

它告诉我“无法从“匿名方法”转换为“System.Delegate”,而当我将匿名方法转换为委托时它确实有效?

BeginInvoke((progressDelegate)delegate { bgWorker_ProgressChanged(sender, e); });

【问题讨论】:

标签: c# .net delegates .net-2.0 anonymous-methods


【解决方案1】:

Delegate 类是委托类型的基类。但是,只有系统和编译器可以从 Delegate 类或 MulticastDelegate 类显式派生。也不允许从委托类型派生新类型。 Delegate 类不被视为委托类型;它是一个用于派生委托类型的类。 来源——MSDN

因此需要显式强制转换为派生自委托类型。当您为 System.Delegate 类型的参数传递匿名方法时,您会遇到这个特定的编译器错误——幸运的是,这种情况很少见。这太灵活了。

delegate void MyDelegate();

  static void DoSomething_Flexible(Delegate d)
  {   d.DynamicInvoke();      }
  static void DoSomething_Usable(MyDelegate d)
  {   d();      }
  static void Main(string[] args)
  {
     // requires explicit cast else compile error Error "Cannot convert anonymous method to type 'System.Delegate' because it is not a delegate type    
     DoSomething_Flexible((MyDelegate) delegate { Console.WriteLine("Flexible is here!"); });  

     // Parameter Type is a .NET Delegate, no explicit cast needed here. 
     DoSomething_Usable(delegate { Console.WriteLine("Usable is here!"); });
  }

更多信息请访问this page by Ian Griffith。 (见注释标题后的段落)

【讨论】:

  • 不错的答案,但我不确定我是否会将 SomeControl.BeginInvoke(Delegate method, param object[] args) 描述为 rare
  • @PeterWone - :)。我建议使用 BackgroundWorker 实例来处理 UI 线程关联。您无法对以这种方式编写的现有第三方方法做任何事情 - 您需要使用小型 (Action) 强制转换进行标记
【解决方案2】:

您需要告诉编译器要创建的委托的类型,因为Invoke(等)只采用Delegate(而不是更具体的东西)。

为了适用于最大的受众,MethodInvoker 是一种方便的委托类型

BeginInvoke((MethodInvoker) delegate(...) {...});

但是...BackgroundWorker.ProgressChanged 会自动在 UI 线程上触发 - 所以你甚至不需要这个。

【讨论】:

    【解决方案3】:

    在这些情况下,大多数时候您都在处理无参数委托或谓词。最简单的排序方法是将匿名方法分别直接转换为ActionPredicate;您只是不需要为这样的简单事情创建自定义委托类型。

    所以你会有类似的东西

    BeginInvoke((Action)delegate(){YourCode.DoSomething();});
    

    BeginInvoke((Predicate)delegate(object yourParameter){return YourCode.IsTheParameterSomething(yourParameter)});
    

    HTH

    【讨论】:

      最近更新 更多