【问题标题】:Overload precedence between Expression<Action> and Expression<Action<T>>Expression<Action> 和 Expression<Action<T>> 之间的重载优先级
【发布时间】:2015-06-22 14:08:57
【问题描述】:

短版:

当一个接受Expression&lt;Action&gt;,另一个接受Expression&lt;Action&lt;T&gt;&gt;时,重载两种方法的最佳方式是什么?

加长版:

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

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&lt;...&gt;,因为我们根据表达式树在其他地方做一些魔术。

我的理由是这样的:

  1. 泛型不是真实的 - 它们是编译器技巧
  2. Action&lt;T&gt; 实际上是与Action 非常不同的委托类型
  3. 因此应该调用方法 2,因为编译器拥有进行推理所需的所有信息。

实际发生的情况是我得到一个编译器错误,大意是我试图将一个参数传递给一个不接受任何参数的动作......即。 Method 1 正在成为目标。

附带说明,如果我像这样明确指定泛型参数,这将按预期工作:

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

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

【问题讨论】:

  • “泛型不是真实的——它们是编译器的把戏”:不,它们是真实的。 .NET 已经具体化了泛型,这与使用类型擦除的 Java 不同。
  • 我的真正意思是'在这种情况下泛型并不真实,因为编译器创建了一个新的重整类型来表示Action&lt;T&gt;'......但你是对的:)跨度>
  • 我已经修复了我的答案(之前被严重破坏)但这只能解释现有行为 - 它不能帮助您解决问题,因为我们没有足够的上下文。如果您提供更多背景信息,我们或许可以提供更多帮助。

标签: c# generics overloading


【解决方案1】:

目前,您的两种方法都不适用 - 因为类型推断无法为您的第二种方法推断 T,而第一种方法无效,因为您的匿名函数有一个参数(与 Action 不同)。编译器报告错误,就好像它已经执行了重载决议并选择了第一个方法,但这是错误消息并不能真正说明全部情况的情况之一。

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

Foo(Expression<Action> action, string item)

以及方法2的签名:

Foo<T>(Expression<Action<T>> action, T item)

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

如果这两种方法都适用(例如,在上述更改之后,您将非泛型方法的第一个参数更改为Expression&lt;Action&lt;string&gt;&gt;),就正常而言,它将以平局告终“参数到参数类型”的转换——但是第一条抢七规则(在 C# 5 规范的第 7.5.3.2 节中)是:

  • 如果 MP 是非泛型方法,而 MQ 是泛型方法,则 MP 优于 MQ .

换句话说,在重载决议中,非泛型方法比泛型方法更受青睐。

在修复您当前的代码方面 - 如果没有更多关于您要实现的目标的上下文,很难知道如何做到这一点。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-04
    • 1970-01-01
    相关资源
    最近更新 更多