Eam*_*nne 45 c# inheritance static language-design
在C#中,超类的静态成员被"继承"到子类范围中.例如:
class A { public static int M() { return 1; } }
class B : A {}
class C : A { public new static int M() { return 2; } }
[...]
A.M(); //returns 1
B.M(); //returns 1 - this is equivalent to A.M()
C.M(); //returns 2 - this is not equivalent to A.M()
Run Code Online (Sandbox Code Playgroud)
现在,你不能继承静态类,我唯一可以想象静态继承可能重要的地方完全忽略它:尽管你可以创建一个通用约束,它需要一个类型参数T作为子类A,你仍然无法调用T.M()(这可能简化了VM的事情,更不用说M在子类中编写不同的实现并使用它.
因此,静态成员的"继承"仅仅看起来像命名空间污染; 即使你明确限定名称(即B.M)A的版本仍然解决.
编辑与命名空间的比较:
namespace N1{ class X(); }
namespace N1.N2 { class X(); }
namespace N1.N2.N3 { [...] }
Run Code Online (Sandbox Code Playgroud)
内部N1.N2.N3是有意义的,如果我X没有资格使用它指的是N1.N2.X.但是,如果我明确提到N1.N2.N3.X- 并且没有这样的类存在 - 我不希望它找到它N2的版本; 实际上,如果您尝试这样做,编译器会报告错误.相比之下,如果我明确提到B.M(),为什么编译器报告错误?毕竟,"B"中没有"M"方法......
这种继承有什么作用?这个功能可以以某种方式建设性地使用吗?
Dan*_*ker 25
因此,静态成员的"继承"仅仅看起来像命名空间污染
这是正确的,除了一个人的污染是另一个人添加辣味.
我认为Martin Fowler在他的DSL工作中建议以这种方式使用继承来方便地访问静态方法,允许在没有类名认证的情况下使用这些方法.因此,调用代码必须位于继承定义方法的类的类中.(我认为这是一个糟糕的主意.)
在我看来,静态成员不应该被混合到一个具有非静态目的的类中,你在这里提出的问题是为什么重要的是不混合它们的部分原因.
在其他"实例"类的实现中隐藏私有静态可变数据尤其可怕.但是有静态方法,甚至是更糟糕的混音器.以下是混合到类中的静态方法的典型用法:
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();
}
}
Run Code Online (Sandbox Code Playgroud)
这是静态工厂方法模式.大部分时间都没有意义,但更糟糕的是现在我们有了这个:
public class AnotherThing : Thing { }
Run Code Online (Sandbox Code Playgroud)
现在有一个静态Make方法返回a Thing,而不是a AnotherThing.
这种不匹配强烈暗示任何采用静态方法的东西都应该密封.静态成员无法与继承很好地集成.将它们遗传是没有意义的.所以我把静态的东西保存在不同的静态类中,当我已经说过这个类是静态的时候,我抱怨冗余必须声明每个成员静态.
但这只是现在太迟了的事情之一.所有真正的工作语言(以及图书馆和产品)都有一些.C#的数量非常少.
Lui*_*ipe 10
我宁愿访问派生类中所有基于静态的成员.否则,我需要确切地知道静态成员的定义,并明确地调用它.
使用Intellisense时,您可以自动了解该类所有可用的静态成员.
当然,它们不是遗传的,它只是一种捷径
这就是它的工作原理,在大多数情况下可能只是一个愚蠢的答案.但在这种情况下,它是如何工作的; 因为你是从A派生的,所以你说你是A +你添加的额外功能.
因此,您需要能够访问通过A实例的相同变量.
但是,在访问静态成员/ fields /方法时,继承静态类是没有意义的.
这方面的一个例子如下:
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; }
}
Run Code Online (Sandbox Code Playgroud)
测试看起来像这样:
User.DefaultUserPool = "Test";
BaseUser.DefaultUserPool = "Second Test";
Console.WriteLine(User.DefaultUserPool);
Console.WriteLine(BaseUser.DefaultUserPool);
Run Code Online (Sandbox Code Playgroud)
两个WriteLines都输出"Second Test",这是因为BaseUser和User都应该按照设计使用DefaultUserPool .并且重写静态实现的方法不会使mucn有意义,因为它只是子类中的一个访问器.
只可以有一个人.覆盖它意味着该子类有一个新的实现,这将杀死术语"静态".
实际上,据我所知,这只是编译器提供的快捷方式.语法糖.B.M()将只编译,A.M()因为B没有static M()A和A.这是为了更容易写作,没有别的.没有"静态继承".
补充:并且new"重新定义" 的要求只是为了让你不小心射击自己.