为什么静态和非静态方法不能共享相同的签名?

Yog*_*ele 11 c# polymorphism

C#提供了在函数重载时使用的以下签名特征.

我们知道,重载只考虑参数; 它们的数量和类型,但多态性的目标是根据调用策略提供相同的名称但不同的用法.

如果我有一个包含两个具有相同名称和签名的方法的类,而一个是静态而另一个不是,则C#编译器会抛出错误; "类已经定义了一个名为'foo'的成员,它具有相同的参数类型".对这两种方法的调用将会有所不同; 一个具有对象名称,另一个具有类名称.因此,呼叫策略没有歧义.那为什么会抛出错误?

 class Example {

    public void foo() { }
    public static void foo() { }

}

class Program
{
    static void Main(string[] args)
    {

        Example e = new Example();
        e.foo(); 

    }
}
Run Code Online (Sandbox Code Playgroud)

Mic*_*ael 13

它抛出错误的原因是可以从非静态方法调用静态方法而不指定类型名称.在这种情况下,编译器将无法确定调用哪个方法.

public class Foo()
{
   public static void MyMethod() {};
   public void MyMethod() {}

   public void SomeOtherMethod()
   {
      MyMethod(); // which method we're calling static or non-static ?
   }
}
Run Code Online (Sandbox Code Playgroud)

编辑

刚刚找到关于你案件的SO帖子.您可能还想检查它.

  • 但是,您可以声明一个与现有字段同名的局部变量.你可以使用`this`明确地引用那个字段.这将是相同的 - this.MyMethod - 实例; MyMethod或Foo.MyMethod - 静态. (6认同)

use*_*740 5

发生此错误是因为这是在C#语言规范中定义行为的方式.任何"含糊不清"的用法(或消除歧义的方法)都是无关紧要的,尽管这种推理和边缘情况可能导致设计者没有明确允许这样的区别......或者它可能只是基础.NET CLI的C#编码/ CLR限制1.

从C#规范中的"3.6签名和重载"(并与链接文档一致),格式化为项目符号:

方法的签名包括

  • 方法的名称,
  • 类型参数的数量,和
  • 每个形式参数的类型和种类(值,参考或输出) ..

方法改性剂,其中包括static,都不会认为这里的方法签名的一部分.

而且,从"1.6.6方法"我们有限制和同意摘要:

方法的签名在声明方法的类中必须是唯一的.方法的签名包括方法的名称,类型参数的数量以及{参数的数量,修饰符和类型}.

此限制适用于考虑多态性的方法之前(并且独立于此).

另外,作为结束语:实例方法必须是虚拟的,或者通过接口访问,以便在C#中运行时是多态的.(方法隐藏和方法重载都可以说是编译时多态的一种形式,但这是另一个主题..)


1对此的支持仅仅是因为.NET CLI/CLR本身的限制而不值得绕过(即出于互操作性原因).从ECMA-335中的 "I.8.6.1.5方法签名" :

方法签名由

  • 调用约定[CLS规则15:" CLS支持的唯一调用约定是标准的托管调用约定"],
  • 通用参数的数量,如果方法是通用的,
  • [省略规则]
  • 一个零个或多个参数签名的列表 - 一个用于方法的每个参数 - 和
  • 结果值的类型签名(如果生成一个).

方法签名由方法定义声明.除了参数签名之外,只能向方法签名添加一个约束 [CLS规则15:"vararg约束不是 CLS的一部分"]:

  • 可以包含vararg约束以指示超过此点的所有参数都是可选的.当它出现时,调用约定应该是支持变量参数列表的约定.

因此,C#/ CLS和ECMA签名组件之间的交集是方法名称,"通用参数的数量"和"零个或多个参数签名的列表".