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参数T
是A
的子类,但你仍然不能调用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的接口。