C#静态成员“inheritance” – 为什么这存在呢?

在C#中,超类的静态成员被“inheritance”到子类作用域中。 例如:

class A { public static int M() { return 1; } } class B : A {} class C : A { public new static int M() { return 2; } } [...] AM(); //returns 1 BM(); //returns 1 - this is equivalent to AM() CM(); //returns 2 - this is not equivalent to AM() 

现在,你不能inheritance静态类,唯一可以想象静态inheritance可能重要的地方是完全忽略它:尽pipe你可以创build一个通用约束,要求types参数TA的子类,但你仍然不能调用TM() (这可能简化了虚拟机的事情),更不用说在一个子类中写一个不同的M实现并使用它。

所以,静态成员的“inheritance”只不过是名字空间的污染; 即使您明确地限定了名称(即BM ), A的版本仍然得到解决。

编辑与命名空间比较:

 namespace N1{ class X(); } namespace N1.N2 { class X(); } namespace N1.N2.N3 { [...] } 

N1.N2.N3内是有道理的,如果我使用X而没有限定,它是指N1.N2.X 但是,如果我明确指出N1.N2.N3.X – 并且不存在这样的类 – 我不指望它findN2的版本; 如果你尝试这个,确实给编译器报告一个错误。 相比之下,如果我明确提到BM() ,编译器为什么不报告错误? 毕竟,“B”中没有“M”的方法…

这个inheritance有什么目的? 这个function可以以某种方式build设性地使用吗?

所以,静态成员的“inheritance”只是名字空间的污染

没错,除了一个人的污染是另一个人添加辛辣的味道。

我认为马丁·福勒(Martin Fowler)在他的DSL工作中提出了以这种方式使用inheritance来允许方便地访问静态方法,允许这些方法在没有类名限定的情况下使用。 所以调用代码必须位于inheritance定义方法的类中。 (我认为这是一个烂的想法。)

在我看来,不应该把静态成员混入一个非静态目的的类中,这里提出的问题是不混合它们的一个重要原因。

隐藏私有的静态可变数据在其他“instancey”类中的实现是特别可怕的。 但是,然后有静态方法,这是更糟糕的搅拌机。 下面是静态方法的一个典型应用:

 public class Thing { // typical per-instance stuff int _member1; protected virtual void Foo() { ... } public void Bar() { ... } // factory method public static Thing Make() { return new Thing(); } } 

这是静态工厂方法模式。 大部分时间是毫无意义的,但更糟糕的是,现在我们有了这个:

 public class AnotherThing : Thing { } 

这现在有一个静态的方法返回一个Thing ,而不是AnotherThing

这种不匹配强烈地暗示着任何有静态方法的东西都应该被封闭。 静态成员不能很好地与inheritance集成。 让它们遗传是没有意义的。 所以我把静态的东西保存在单独的静态类中,当我已经说过这个类是静态的时候,我不得不声明每个静态成员都是静态的。

但这只是其中之一 – 现在的事情。 所有真实的工作语言(以及库和产品)都有其中的一些。 C#显然很less。

我更愿意访问派生类中的所有基于静态成员。 否则,我需要确切地知道静态成员的定义,并明确地调用它。

当使用Intellisense时,你可以自动知道每一个静态成员可用于这种类。

当然,它们不是遗传的,它只是一个捷径

这是如何工作的 ,在大多数情况下可能只是一个愚蠢的答案。 但在这种情况下,它是如何工作的; 既然你从A派生出来,你就说你是A +你添加的额外特征。

因此,您需要能够访问与通过A的实例相同的variables。

但是,在访问静态成员/字段/方法时,inheritance静态类没有任何意义。

一个例子如下:

 internal class BaseUser { public static string DefaultUserPool { get; set; } } internal class User : BaseUser { public int Id { get; set; } public string Name { get; set; } public User Parent { get; set; } } 

testing看起来像这样:

 User.DefaultUserPool = "Test"; BaseUser.DefaultUserPool = "Second Test"; Console.WriteLine(User.DefaultUserPool); Console.WriteLine(BaseUser.DefaultUserPool); 

两个WriteLines都输出“Second Test”,这是因为BaseUser和User都应该使用DefaultUserPool。 而重写静态实现的方法并不会产生任何意义,因为它只是一个子类中的访问器。

只能有一个。 覆盖它意味着这个子类有一个新的实现,这将杀死“静态”一词。

实际上,据我所知,这只是编译器提供的一个捷径。 语法糖。 BM()只会编译成AM()因为B没有static M()和A。 这是为了更容易的写作,没有别的。 没有“静态inheritance”。

补充说: “重新定义”的new要求只是为了让你不小心把自己打到脚上。

我认为这是为了访问基类的受保护的静态成员。

 class Base { protected static void Helper(string s) { Console.WriteLine(s); } } class Subclass : Base { public void Run() { Helper("From the subclass"); } } 

我总是看到它阻止任何forms的多态性的inheritance类的那些项目,你希望保留所有子类相同的function。

由于某种原因,我忽略了上面的内容,我正在考虑密封而不是静态

我想你会使用静态成员variables和函数,以确保任何数据或函数都不依赖于一个类实例,因为它只会被实例化一次。

一个使用的例子就是一个计数器值,它将保持超类的所有子类的实例(每个子类在构造上递增静态计数值)。 这个计数值对于子类的所有实例是可用的和相等的。

所以…有什么select?

这个问题提到…

为什么编译器不报告错误? 毕竟,“B”中没有“M”的方法…

但在“B”类中有一个派生的“M”方法。

如果编译器没有向编程人员提供一个统一的基本情况下的虚拟表,那么程序员将不得不通过基本types寻找静态方法。 这将打破多态 。

维基百科…

在面向对象的编程环境中,几乎被普遍称为多态的子types多态是一种typesA的能力出现并被用作另一种typesB …。

在强types语言中,多态性通常意味着typesA以某种方式从B类派生,或者typesC实现了一个代表typesB的接口。