【问题标题】:Question about ambiguous calls in C#关于 C# 中模糊调用的问题
【发布时间】:2010-10-27 14:05:32
【问题描述】:

我有一个问题,但不是什么大问题,但让我有点好奇。

我有一个类,里面有两个方法。一种是静态方法,另一种是实例方法。这些方法具有相同的名称。

public class BlockHeader
{
    public static BlockHeader Peek(BinaryReader reader)
    {
        // Create a block header and peek at it.           
        BlockHeader blockHeader = new BlockHeader();
        blockHeader.Peek(reader);
        return blockHeader;
    }

    public virtual void Peek(BinaryReader reader)
    {
        // Do magic.
    }
}

当我尝试构建我的项目时,我收到一条错误消息:

调用之间有歧义 以下方法或属性: 'MyApp.BlockHeader.Peek(System.IO.BinaryReader)' 和 'MyApp.BlockHeader.Peek(System.IO.BinaryReader)'

我知道方法签名实际上是相同的,但我看不出我怎么可能直接从实例成员调用静态方法。

我认为这有一个很好的理由,但有人知道这是什么原因吗?

【问题讨论】:

  • 我认为这是因为 J# 和其他语言确实允许您从实例成员调用静态方法。 CLR 必须强制执行最低公分母。
  • 我也觉得这很奇怪。规范非常清楚这种行为是正确的。请参阅第 7.5.5.1 节,内容如下:“如果最好的方法是静态方法,则方法组必须来自简单名称或通过类型的成员访问......”注意该位是如何发生的 AFTER我们找出“最佳”方法的地方。在检查静态性之前,首先明确计算“最佳”。因此,最佳性不考虑静态性,在您的情况下,无法确定最佳方法。因此,歧义错误。
  • 不管怎样,你问的原因。这种看似奇怪的行为的原因是为了解决我们所说的“颜色问题”。当您有“Color Color = Color.Red; Color.Foo();”时,这是否意味着“在 Color 类型上调用静态方法 Foo”,还是意味着“在本地 Color 上调用实例方法 Foo”?编译器允许两者,因此在解析 Foo 之前无法确定“Color.Foo()”中“Color”的含义。这意味着必须在我们确切知道“颜色”的含义之前解决 Foo 问题。在您的情况下,无法明确解决。
  • 有关颜色颜色问题的更多信息,请参见第 7.5.4.1 节。
  • Eric Lippert:您应该将您写的内容复制到答案中,以便我可以将其设置为接受的答案。

标签: c# .net ambiguous-call


【解决方案1】:

C# 设计的一般策略是强制您指定可能存在歧义的地方。面对重构工具,它允许人们在瞬间调整事物是否是静态的,这种立场是很好的——尤其是对于这样的情况。您会看到许多其他类似的情况(覆盖与虚拟、新的阴影等)。

一般来说,消除这种混乱的空间会使代码更清晰,并迫使你保持你的房子井井有条。

编辑:A good post from Eric Lippert discusses another reason for this ambiguity leading to the error you saw

【讨论】:

  • 经典示例(在本例中)是调用 Peek(...); 的实例方法;是这个。偷看?还是 BlockHeader.Peek?
【解决方案2】:

这是 C# 3.0 语言规范的摘录。

方法的签名在声明该方法的类中必须是唯一的。方法的签名由方法的名称、类型参数的数量及其参数的数量、修饰符和类型组成。方法的签名不包括返回类型。

“静态”修饰符不是签名的一部分,因此您的示例违反了此唯一签名规则。

不过,我不知道这条规则背后的原因。

【讨论】:

    【解决方案3】:

    我认为没有技术上的理由来禁止它,但这样做更多是为了保护程序员免受自己的伤害。考虑以下示例:

    public static void Main()
    {
      BlockHeader BlockHeader = new BlockHeader();
      BlockHeader.Peek();
    }
    

    上面的例子完全有效,但如果你描述的情况是允许的,它是否可读?你能一眼看出是调用了实例方法还是静态方法?

    【讨论】:

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