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();
}
}
我觉得你的问题是“为什么标准选择禁止声明两种仅因静态关键字而不同的方法?”,因此“因为标准这么说”的答案对我来说并不合适。
现在,问题是,可能有任何原因。标准就是法律,它可以是任意的。如果没有参与语言设计的人的帮助,我们所能做的就是推测原因,试图揭示法律的精神。
这是我的猜测。我认为这一选择有三个主要原因:
C和Java是C#的鼓舞人心的语言,遵守与这些语言相同的重载规则是有意义的。至于为什么在这些语言中是这样,我不知道。关于C,我发现了一个类似的问题,尽管没有回答为什么会这样(在“标准这么说”之外)。
正如其他人和OP所指出的,允许除了static关键字之外的相同签名会强制用户以明确的方式调用方法(通过在类名或实例名前加前缀)。这增加了代码的复杂性。当然,这可以通过字段和参数来完成。但是,有些人不同意这种用法,他们更喜欢为字段选择不同的名称(在字段前面加上u或m_u)。
这是我在这里的理解,所以我可能完全错了(至少@user2864740认为这个参数是可疑的——请参阅注释),但我觉得静态成员是在OOP中引入“函数式编程”的一种方式。它们不绑定到特定的实例,因此它们不会修改对象的内部状态(如果它们修改另一个对象的状态,那么它们应该是该另一个对象的非静态方法),以一种“纯”的方式。因此,我不理解“纯函数”在语义上如何与常规对象方法足够接近,从而使它们共享相同的名称。
发生此错误是因为这是C语言规范中定义行为的方式。任何“模棱两可”的用法(或消除歧义的方法)都是不相关的,尽管这种推理和边缘案例可能导致设计师不明确允许这种区别。。或者,它可能只是一种对基础数据的C#编目。NET CLI/CLR限制1。
从C#规范中的3.6签名和重载(与链接留档一致),格式化为项目符号:
方法的签名包括
方法修饰符(包括static
)在此不被视为方法签名的一部分。
从“1.6.6方法”中,我们得到了限制和一致的总结:
方法的签名在声明该方法的类中必须是唯一的。方法的签名由方法的名称、类型参数的数量和{其参数的数量、修饰符和类型}组成。。
此限制适用于多态性所考虑的方法之前(且独立于该方法)。
另外,作为结束语:实例方法必须是虚拟的或通过接口访问,才能在C#中运行时多态。(方法隐藏和方法重载可以说是编译时多态性的一种形式,但这是另一个主题。)
1有人支持这一点,这仅仅是由于限制了。NET CLI/CLR本身不值得绕过(即出于互操作性原因)。来自ECMA-335中的“I.8.6.1.5方法签名”:
方法签名由
方法签名由方法定义声明。除了参数签名的约束外,只能向方法签名添加一个约束[CLS规则15:“vararg约束不是CLS的一部分”]:
因此,C#/CLS和ECMA签名组件之间的交集是方法名、“通用参数的数量”和“零个或多个参数签名的列表”。
它抛出错误的原因是,可以从非静态方法调用静态方法,而无需指定类型名。在这种情况下,编译器将无法确定调用哪个方法。
public class Foo()
{
public static void MyMethod() {};
public void MyMethod() {}
public void SomeOtherMethod()
{
MyMethod(); // which method we're calling static or non-static ?
}
}
编辑
刚找到这篇关于你的案子的帖子。你可能也想检查一下。
问题内容: 请参见下面的代码段: 代码1 代码2 这些代码段之间有什么区别?两者都15作为答案输出。 问题答案: 静态方法属于类本身,而非静态(aka实例)方法属于从该类生成的每个对象。如果你的方法执行的操作不依赖于其类的单个特征,请将其设置为静态(这将使程序的占用空间减小)。否则,它应该是非静态的。 例: 你可以像这样调用静态方法:。如果你使用method2尝试该操作,它将失败。但这将起作用:;
我真的对此感到困惑!我有2个班,俱乐部和会员。在Membership中,我有方法getMonth();在Club中,我有joinedMonth(),它接受参数'month'--所以用户输入一个月,然后我希望它返回在该特定月份加入的成员资格。 我试图从Club类调用getMonth()方法,这样我就可以继续比较月份的整数。但是,当我试图调用该方法时,我只得到提到的“非静态方法getMonth()不能
问题内容: 为什么我们不能在非静态内部类中使用静态方法? 如果我将内部类设为静态,则可以工作。为什么? 问题答案: 因为内部类的实例与外部类的实例隐式关联,所以它本身不能定义任何静态方法。由于静态嵌套类无法直接引用其封闭类中定义的实例变量或方法,因此只能通过对象引用使用它们,因此在静态嵌套类中声明静态方法是安全的。
我有点困惑。请看看下面的代码。 我确信调用此序列是可能的。 虽然我仍然有一个小小的困惑,但我们可以很容易地看到也调用方法,这是一个静态方法。方法 是调用非同步静态方法的静态同步方法。当 thread-2 获得类级锁时,为什么从 Thread-1 调用 没有被阻止? 我只是在逻辑上感到困惑,如果一个线程获得类级锁定,则该类其他非同步静态方法保持打开状态,以便从其他方法(实例方法)调用。为什么?
问题内容: 我知道不可能在一个类中重写一个方法。但是,有没有办法使用非静态方法作为静态方法呢?例如,我有一个加数字的方法。我希望此方法在没有对象的情况下有用。是否可以在不创建其他方法的情况下执行类似的操作? 编辑:我的意思是,如果我将一个方法设为静态,我将需要它接受参数,如果我创建了一个已经设置了变量的对象,那么再次对具有相同参数的对象调用函数将非常不舒服。 我知道代码不正确,但是我想展示自己想做
PowerMockito.when(ConnectionFactory.getConn(“ABC”).getCurrentStatus()).thenReturn(ConnectionStatus.Connected); 对于上面的陈述,我得到了一个NPE。 我在junit测试类的开头已经有@PrepareForTest({fxallConnectionFactory.class,Connecti