【问题标题】:delegate , action and passing lambda expression as delegate parameter委托、动作和传递 lambda 表达式作为委托参数
【发布时间】:2015-03-06 19:59:25
【问题描述】:

我看过这个问题diference between delegate and action

我仍然想知道为什么我可以将 lambda 表达式传递给接受 Action 类型参数的方法
而我不能将 lambda 表达式传递给接受委托类型参数的方法
我有这个 Print 方法,我将使用 action 和 Delegate 来引用它

public static void Print()
{
    Console.WriteLine("Printing ..");
}

我创建了这两个方法,它们将调用 Print 方法,如您所见,第一个具有 Action 类型参数,第二个具有 Delegate 类型参数,这些参数将引用方法“Print”

public static void ActionParamMethod(Action DAction)
{
    DAction();
}
public static void DelegateParamMethod(Delegate SomeDelegate)
{

}

我要将 lambda 表达式传递给这些方法

public static void SomeHowMethod()
{
    DelegateParamMethod(() => Print());
    ActionParamMethod(() => Print());
}

当我尝试将 lambda 表达式传递给接受 Delegate 参数的方法时,我收到此错误

无法将 lambda 表达式转换为类型“System.Delegate”,因为它 不是委托类型

为什么它不是委托类型而 Action 是委托类型?
为什么我可以将 lambda 表达式传递给接受 Action 参数的方法,但我不能将 lambda 表达式传递给接受 Delegate 参数的方法?

【问题讨论】:

    标签: c# lambda delegates


    【解决方案1】:

    Lambda 需要根据上下文推断所使用的委托的实际类型。当尝试在预期 Delegate 的上下文中使用 lambda 时,lambda 的推理算法无法确定它应该是哪种特定类型的委托。这就像试图构造一个接口的实例;你不会知道选择哪个实现。

    【讨论】:

      【解决方案2】:

      原因是 lambda 表达式C# 中没有类型,除非您将它们强制转换为具体类型。

      Delegate 类型是所有代表的基类。它是一个abstract 类。除非您指定像 ActionFunc 这样的实际委托类型,否则您不能将 lambda 表达式作为 Delegate 传递。这就像你不能实例化一个抽象类,但你可以传递一个实现它的类作为参数。如果您将 lambda 转换为任何委托类型,它将按预期工作:

      DelegateParamMethod((Action<string>)(x => Console.WriteLine(x));
      

      你的第一种方法之所以能在没有指定类型的情况下工作,是因为表达式可以转换为Action,否则它不会有效,原因与此表达式无效的原因相同:

      var x = () => Print("Hello world");
      

      【讨论】:

      • 这是否意味着lambda表达式可以隐式转换为Action但不能隐式转换为Delegate,如果参数类型为Delegate,我应该将它们显式转换为Action类型?
      【解决方案3】:

      问题在于您没有提供要调用的委托类型。您正在寻找类似的东西:

      DelegateParamMethod((Action)(() => Print()));
      

      【讨论】:

        【解决方案4】:

        您不应在代码中引用Delegate,它是委托的基类,但不能像您在此处那样使用。

        您应该选择一个委托类型(例如您的 Action 示例)并将其用作参数。

        【讨论】:

        • 虽然使用Delegate 一定要小心,但它确实有它的用途。如果您真的希望能够接受任何委托而不考虑其签名,那么这就是您需要使用的。适当使用它当然很少见,但它们确实存在。另请注意,这实际上并不能回答问题。最多应该是一条评论。
        • @Servy:在澄清这样的观点时,我更喜欢绝对。用“通常”给所有东西加上胡椒粉往往会使这一点变得模糊。如果您不了解委托和 Delegate 之间的区别,那么可以肯定地说“永远不要使用后者”,因为这需要很长时间才能使用。
        • @Servy:什么不正确的信息?除非您正在执行多线程 Windows 窗体逻辑,否则您可能不应该使用 Delegate(这是进入 UI 线程的最简单方法)。在大多数情况下,接受 Action 并需要 lambda 包装器会比尝试使用原始 Delegate 更直接地解决您的问题。
        • @MadMass:Windows 窗体需要从 UI 线程调用某些方法,因为它们不是线程安全的。有一些方法可以使用 BeginInvoke 来确保从正确的线程调用这些方法。但是,您始终可以从 Action 或任何其他委托中获得 Delegate,因为它是基类,因此您永远不会被抛弃。
        • @Guvante 在很多情况下,是的,它会的。但并非所有使用委托的情况都涉及在编译时已知的委托签名。在这种情况下必须使用Delegate
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-11-17
        • 2011-05-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多