表达式<action>和Expression <action <t>之间的重载优先级&gt;

时间:2015-06-22 14:08:58

标签: c# generics overloading

简短版本:

当一个人接受Expression<Action>而另一个人接受Expression<Action<T>>时,重载两种方法的最佳方法是什么?

版本较长:

假设我在(设计糟糕的)类中有以下方法:

void Main()
{
    Foo(t => Bar(t));
}

void Foo(Expression<Action> action)
{
    "Method 1!".Dump();
}

void Foo<T>(Expression<Action<T>> action)
{
    "Method 2!".Dump();
}

void Bar(String thing)
{
    // Some bar-like thing
}

现在,可能是我特别昏暗,但我希望从Main方法调用'方法2'。

对此的唯一限制是我需要传递Expression<...>,因为我们在其他地方根据表达式树做了一些魔法。

我的理由是这样的:

  1. 泛型不是真的 - 它们是编译器技巧
  2. Action<T>实际上是与Action
  3. 完全不同的委托类型
  4. 因此,应该调用方法2,因为编译器具有进行推理所需的所有信息。
  5. 实际发生的是我得到一个编译器错误,我试图将一个参数传递给一个不接受任何参数的Action ...即。 Method 1正在成为目标。

    在旁注中,如果我明确指定泛型参数,这将按预期工作:

    Foo<String>(t => Bar(t));
    

    您对此的看法将不胜感激!

1 个答案:

答案 0 :(得分:5)

目前,您的两种方法都不适用 - 因为类型推断无法推断出第二种方法T,第一种方法无效,因为您的匿名函数有一个参数(与{{1}不同})。编译器报告错误,好像它已经执行了重载决策并选择了第一种方法,但它是错误消息并不能真正讲述整个故事的其中一种情况。

如果将方法1的签名更改为:

Action

和方法2的签名:

Foo(Expression<Action> action, string item)

然后类型推断将起作用,并且将调用第二种方法(因为第一种方法不适用)。

如果这两种方法都适用(例如,在上述更改之后,您将非通用方法的第一个参数更改为Foo<T>(Expression<Action<T>> action, T item) ),则最终会以平局为准正常&#34;参数类型的参数&#34;转换 - 但是第一个打破平局规则(在C#5规范的第7.5.3.2节中)是:

  
      
  • 如果M P 是非泛型方法且M Q 是通用方法,则M P 优于M Q
  •   

换句话说,在泛载分辨率方面,非泛型方法比泛型方法更受青睐。

在修复当前代码方面 - 如果没有更多关于您正在努力实现的内容的背景,很难知道如何做到这一点。