我有几个不需要任何状态的类。从组织的角度来看,我想把它们放进一个层次结构中。
但似乎我不能为静态类声明继承关系。
就像这样:
public static class Base
{
}
public static class Inherited : Base
{
}
这是行不通的。
为什么语言设计者关闭了这个可能性呢?
我有几个不需要任何状态的类。从组织的角度来看,我想把它们放进一个层次结构中。
但似乎我不能为静态类声明继承关系。
就像这样:
public static class Base
{
}
public static class Inherited : Base
{
}
这是行不通的。
为什么语言设计者关闭了这个可能性呢?
来自这里的引文:
这实际上是设计如此。似乎没有理由继承静态类。您始终可以通过类名称本身访问其公共静态成员。我看到的唯一继承静态内容的原因是糟糕的,例如节省输入的几个字符。
有理由考虑直接将静态成员带入作用域的机制(事实上,在 Orcas 产品周期之后,我们将考虑此问题),但是静态类继承不是正确的方法:它是使用的错误机制,并且仅适用于恰好驻留在静态类中的静态成员。
(Mads Torgersen,C# 语言 PM)
来自 channel9 的其他意见
.NET 中的继承仅基于实例。 静态方法是在类型级别而不是在实例级别定义的。这就是为什么无法覆盖静态方法/属性/事件的原因...
静态方法只在内存中保留一次。没有为它们创建虚拟表等。
如果在 .NET 中调用实例方法,则始终提供当前实例。这由 .NET 运行时隐藏,但它确实发生了。 每个实例方法都有一个指向执行该方法的对象的指针(引用)作为第一个参数。这不会发生在静态方法中(因为它们是在类型级别定义的)。编译器应该如何决定选择要调用的方法?
(littleguru)
作为一种有价值的想法,littleguru 有一个部分“解决”此问题的方法:单例模式。
object
,每个人都应该知道这一点。因此,无论你是否显式指定,静态类 始终 继承自 object
。 - RenniePetstatic class Foo { }
编译成这个IL:
.class private abstract auto ansi sealed beforefieldinit Foo
extends [mscorlib]System.Object
{
}
从这个角度来看:您可以通过类型名称访问静态成员,如下所示:
MyStaticType.MyStaticMember();
如果你从那个类继承,你必须通过新的类型名称来访问它:
MyNewType.MyStaticMember();
因此,当在代码中使用新项目时,它与原始项目没有任何关系。这将无法利用继承关系,例如多态性。SomeClass<T> where T:Foo
可以访问Foo
的成员,并且如果T
是覆盖了Foo
的一些虚拟静态成员的类,则泛型类将使用这些覆盖。甚至可以定义一种约定,使语言可以以与当前CLR兼容的方式执行此操作(例如,具有这些成员的类应定义一个包含这样的实例成员以及保护非静态类的静态字段,其中包含该类型的实例)。 - supercat您可以使用组合代替...这样可以让您从静态类型中访问类对象。但仍然无法实现接口或抽象类。
一种解决方法是不使用静态类,而是隐藏构造函数,这样类的静态成员是类外唯一可访问的内容。结果就是一个可继承的“静态”类:
public class TestClass<T>
{
protected TestClass()
{ }
public static T Add(T x, T y)
{
return (dynamic)x + (dynamic)y;
}
}
public class TestClass : TestClass<double>
{
// Inherited classes will also need to have protected constructors to prevent people from creating instances of them.
protected TestClass()
{ }
}
TestClass.Add(3.0, 4.0)
TestClass<int>.Add(3, 4)
// Creating a class instance is not allowed because the constructors are inaccessible.
// new TestClass();
// new TestClass<int>();
很不幸,由于“设计上的”语言限制,我们无法做到:
public static class TestClass<T>
{
public static T Add(T x, T y)
{
return (dynamic)x + (dynamic)y;
}
}
public static class TestClass : TestClass<double>
{
}
public abstract class StaticBase<TSuccessor>
where TSuccessor : StaticBase<TSuccessor>, new()
{
protected static readonly TSuccessor Instance = new TSuccessor();
}
public class Base : StaticBase<Base>
{
public Base()
{
}
public void MethodA()
{
}
}
public class Inherited : Base
{
private Inherited()
{
}
public new static void MethodA()
{
Instance.MethodA();
}
}
Inherited
类本身并非静态类,但我们不允许创建它。它实际上继承了静态构造函数,该函数构建了 Base
,并使得 Base
的所有属性和方法都可以作为静态调用。现在唯一要做的就是为需要暴露给静态上下文的每个方法和属性创建静态包装器。
缺点是需要手动创建静态包装器方法和使用 new
关键字。但这种方法有助于支持与静态继承非常相似的功能。
P.S. 我们用它来创建编译查询,但实际上可以用 ConcurrentDictionary 替换它,但静态只读字段及其线程安全已足够好。
public static class MyStaticBase
{
SomeType AttributeBase;
}
public static class MyStaticChild : MyStaticBase
{
SomeType AttributeChild;
}
// ...
DoSomethingTo(MyStaticBase.AttributeBase);
// ...
可能会影响与之相同的存储空间。
// ...
DoSomethingTo(MyStaticChild.AttributeBase);
// ...
非常混乱!
但是等等!如果MyStaticBase和MyStaticChild都在其中定义了相同的签名,编译器会如何处理?如果子类进行了覆盖,那么我的上面的示例将不会改变相同的存储,也许?这会导致更多的混乱。
我认为对于静态继承有一个强有力的信息空间理由。接下来会更多地介绍限制。这个伪代码显示了价值:
public static class MyStaticBase<T>
{
public static T Payload;
public static void Load(StorageSpecs);
public static void Save(StorageSpecs);
public static SomeType AttributeBase
public static SomeType MethodBase(){/*...*/};
}
然后你得到:
public static class MyStaticChild : MyStaticBase<MyChildPlayloadType>
{
public static SomeType AttributeChild;
public static SomeType SomeChildMethod(){/*...*/};
// No need to create the PlayLoad, Load(), and Save().
// You, 'should' be prevented from creating them, more on this in a sec...
}
使用方法如下:
// ...
MyStaticChild.Load(FileNamePath);
MyStaticChild.Save(FileNamePath);
doSomeThing(MyStaticChild.Payload.Attribute);
doSomething(MyStaticChild.AttributeBase);
doSomeThing(MyStaticChild.AttributeChild);
// ...
MyStaticBase<ChildPayload>.SomeBaseField
。但是,由于必须指定通用类型,因此您会受到阻碍。而子类引用则更清晰: MyStaticChild.SomeBaseField
。
我不是编译器的作者,所以我不确定是否遗漏了实现这些限制的困难。尽管如此,我坚信有一个信息空间需要有限的静态继承,而基本答案是由于设计选择不佳(或过于简单)而无法实现。