Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么静态方法隐藏实例方法?_C#_.net - Fatal编程技术网

C# 为什么静态方法隐藏实例方法?

C# 为什么静态方法隐藏实例方法?,c#,.net,C#,.net,以下代码是否应给出警告 class Foo { public void Do() { /*...*/ } /*...*/ } class Bar : Foo { public static void Do() { /*...*/ } /*...*/ } 它给出: “警告CS0108:'Bar.Do()'隐藏继承的成员'Foo.Do()'。如果要隐藏,请使用new关键字。” 如果我对代码进行了更改: class Foo { public static void Do() { /*...*/ }

以下代码是否应给出警告

class Foo { public void Do() { /*...*/ } /*...*/ }
class Bar : Foo { public static void Do()  { /*...*/ } /*...*/ }
它给出:

“警告CS0108:'Bar.Do()'隐藏继承的成员'Foo.Do()'。如果要隐藏,请使用new关键字。”

如果我对代码进行了更改:

class Foo { public static void Do() { /*...*/ } /*...*/ }
class Bar : Foo { public void Do()  { /*...*/ } /*...*/ }
我收到了同样的警告

但是,如果我做了以下更改,警告就会消失

class Foo { public void Do() { /*...*/ } /*...*/ }
class Bar : Foo { new public static void Do() { /*...*/ } /*...*/ }
让我再作修改:

class Foo { public void Do() { /*...*/ } /*...*/ }
class Bar : Foo { 
    new public static void Do() 
    { new Bar().Do();/*...*/ } /*...*/ 
}
这不会编译:

错误CS0176:无法使用实例引用访问成员“Bar.Do()”;请改为使用类型名称限定它

因此,我无法通过静态方法的实例引用访问继承的方法

背后的逻辑是什么?还是我在什么地方打错了


当我试图为从“form”派生的表单定义一个静态方法“Show”时,我遇到了这个问题。

不,这很有意义。这与预期的效果一样:

using System;
using System.Collections.Generic;

class Foo { public void Do() { /*...*/ } /*...*/ }
class Bar : Foo { 
    new public static void Do() 
    { ((Foo)new Bar()).Do();/*...*/ } /*...*/ 
}
这是因为编译器假定您有一个Bar类型,然后查找静态成员。通过将其投射到Foo(免费附带说明),您可以在metdadata for Foo()中看到它,一切都很好。

尝试以下方法:

        new public static void Do()
        { 
            ((Foo)new Bar()).Do(); 
        }

在最后的代码示例中,Bar.Do()声明中的新关键字表示您打算隐藏Foo.Do()。

出于好奇,为什么要这样做?看起来你的解决方案可能走错了方向


上面的代码似乎正常工作,编译器消息告诉您问题所在。

您认为错误在哪里?有警告的事实是绝对正确的。根据C#3.0规范第10.3.4节:

类成员声明是 允许宣布一名成员与 与继承的名称或签名相同 成员。发生这种情况时,派生的 类成员被称为隐藏基 班级成员。隐藏继承的 成员不被视为错误,但 它确实会导致编译器发出 警告要取消显示警告,请单击 派生类的声明 成员可以包含一个新的修改器来 指示派生成员为 用于隐藏基本成员

方法调用失败的事实更微妙,但基本上是因为成员查找算法选择静态方法,然后使用第7.5.5.1节的这一部分:

所选最佳方案的最终验证 方法是:

方法是 在方法的上下文中验证 组:如果最好的方法是静态 方法,方法组必须具有 由一个简单的名称或 通过类型进行成员访问。如果 最好的方法是实例方法 方法组必须是由 简单名称,成员通过 变量或值,或基本访问。 如果这两个要求都不满足 则会发生编译时错误


您应该能够通过调用base.Do()而不是Bar().Do()来调用它。

当我说“new Bar().Do();”我肯定是在调用实例方法“Do”,这在Bar中可以通过Foo获得。那么,为什么我们必须进行类型转换呢?因为编译器不查看实例,而是查看类型元数据。在这里,它只找到一个具有正确签名的方法(名称和空参数列表),这就是静态方法;Bar::Do()映射隐藏了Foo:Do()的映射。Hi Lucero,如果编译器查看类型元数据,那么类型元数据在编译期间可用吗?那么谁首先从代码生成元数据呢?是否有不同的编译过程?McWafflesstix,如果你有时间的话,你能再详细说明一下吗?提前感谢。元数据是由编译器生成的,是的,我假设编译器在内部至少进行2次传递(因为声明的顺序无关紧要)。我的猜测是:词法分析、标记化、元数据/结构创建(所有3个都可以在一个过程中完成)、代码编译(第二个过程)Hi-Jon,+1表示答案。我认为,从语言用户的角度来看,bug妨碍了选择调用的最佳方法:-)。对我来说,“new Bar().Do()”清楚地告诉我在编译时调用哪个方法,并且不需要产生错误!不过,我怀疑另一种选择是使语言更加复杂。如果语言更智能的话,经常会有一些边缘情况可以改进,但是如果语言更智能的话,那么很难“了解”语言,也很难在编译器中正确地实现它。这都是平衡…嗨,乔希,我不想这么做。只是我遇到了这个问题,我想了解C#设计器选择的这种行为。“new Bar().Do()”显然表明正在调用的是实例方法。那么,为什么C#的设计使这一点更加明确呢?有点教育性的问题,我明白了。在这种情况下,您必须认识到,在Bar中,没有名为Do()的实例方法,只有一个静态方法。通过给它起相同的名字,你已经阻止了继承。所以不,实例方法是否被调用并不明显,对我或编译器来说,我想,Bar中有一个实例方法是从Foo派生的。这是我的观点——这不是真的。假设它们都是非静态的。然后,Bar.Do()将隐藏Foo.Do()。也就是说,Foo.Do()不是继承的。不管它是静态的还是实例方法,如果Bar.Do()存在,Foo.Do()不会派生到Bar中。:)我现在理解你了。谢谢同样地,我在寻找逻辑上的原因,为什么它不重要。对于C#(或CLR)设计人员来说,区分静态方法和实例方法是可选的,而他们选择不这样做吗?若否,原因为何?如果是,他们为什么选择不这样做?(尽管我同意这没什么大不了的)