Answers:
从这里引文:
这实际上是设计使然。似乎没有充分的理由继承静态类。它具有公共静态成员,您始终可以通过类名称本身进行访问。我看到的继承静态内容的唯一原因是不好的原因,例如保存了几个打字字符。
也许有理由考虑将静态成员直接带入范围的机制(实际上,我们将在Orcas产品周期之后考虑这一点),但是静态类继承并不是要走的路:这是使用错误的机制,并且有效仅针对碰巧驻留在静态类中的静态成员。
(Mads Torgersen,C#语言PM)
来自channel9的其他意见
.NET中的继承仅在实例基础上起作用。静态方法是在类型级别上定义的,而不是在实例级别上定义的。这就是为什么覆盖不适用于静态方法/属性/事件的原因...
静态方法仅在内存中保存一次。没有为它们创建的虚拟表等。
如果在.NET中调用实例方法,则始终为它提供当前实例。.NET运行时将其隐藏,但是会发生。每个实例方法都有一个指向该方法在其上运行的对象的指针(引用)作为第一个参数。静态方法不会发生这种情况(因为它们是在类型级别定义的)。编译器应如何决定选择要调用的方法?
(小小古鲁)
作为一个有价值的想法,littleguru针对此问题有部分“解决方法”:Singleton模式。
object
,每个人都应该知道这一点。因此,无论您是否明确指定静态类,静态类都始终继承自object
。
无法继承静态类的主要原因是它们是抽象的并且是密封的(这也阻止了它们的任何实例的创建)。
所以这:
static class Foo { }
编译为此IL:
.class private abstract auto ansi sealed beforefieldinit Foo
extends [mscorlib]System.Object
{
}
这样考虑:您可以通过类型名称访问静态成员,如下所示:
MyStaticType.MyStaticMember();
如果要从该类继承,则必须通过新的类型名称访问它:
MyNewType.MyStaticMember();
因此,在代码中使用时,新项目与原始项目没有任何关系。对于诸如多态之类的东西,将无法利用任何继承关系。
也许您认为您只是想扩展原始类中的某些项目。在这种情况下,没有什么会阻止您仅使用全新类型的原始成员。
也许您想向现有静态类型添加方法。您可以通过扩展方法来做到这一点。
也许您希望能够Type
在运行时将静态变量传递给函数并在该类型上调用方法,而又不确切知道该方法的作用。在这种情况下,您可以使用接口。
因此,最后,从继承静态类中实际上并不会获得任何好处。
SomeClass<T> where T:Foo
可以访问的成员Foo
,并且如果T
是覆盖某些虚拟静态成员的Foo
类,则泛型类将使用这些覆盖。甚至有可能定义一个约定,通过该约定,语言可以以与当前CLR兼容的方式来这样做(例如,具有此类成员的类应定义一个受保护的非静态类,其中包含此类实例成员以及一个静态字段)持有该类型的实例)。
您想要通过使用类层次结构实现的目标只能通过命名空间来实现。因此,支持名称空间(如C#)的语言将不使用实现静态类的类层次结构。由于您无法实例化任何类,因此您所需要的只是类定义的层次结构,您可以通过使用命名空间来获得
您可以改用composition ...这将允许您从静态类型访问类对象。但仍然无法实现接口或抽象类
嗯...如果您只是用静态方法填充了非静态类,那会大不相同吗?
您可以使用的解决方法是不使用静态类,而是隐藏构造函数,因此,类的静态成员是在类外部唯一可访问的东西。结果本质上是一个可继承的“静态”类:
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
班是不是静态的本身,但我们不允许创建它。实际上,它继承了builds的静态构造函数Base
,并且所有属性和方法都Base
可以用作静态。现在剩下要做的就是为需要暴露给静态上下文的每个方法和属性制作静态包装器了。
还有一些缺点,例如需要手动创建静态包装器方法和new
关键字。但是这种方法有助于支持与静态继承非常相似的东西。
PS我们用它来创建编译的查询,实际上可以用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
。
我不是编译器作家,所以我不确定是否缺少在编译器中实现这些限制的困难。就是说,我坚信有一个信息空间需要有限的静态继承,而基本的答案是您不能因为设计错误(或过于简单)而无法这样做。
静态类和类成员用于创建无需创建类实例即可访问的数据和函数。静态类成员可用于分离与任何对象标识无关的数据和行为:无论对象发生什么情况,数据和函数均不会更改。当类中没有依赖于对象标识的数据或行为时,可以使用静态类。
可以将一个类声明为静态类,这表明该类仅包含静态成员。无法使用new关键字创建静态类的实例。加载包含静态类的程序或名称空间时,静态类将由.NET Framework公共语言运行时(CLR)自动加载。
使用静态类包含不与特定对象关联的方法。例如,通常需要创建一组不作用于实例数据并且不与代码中的特定对象相关联的方法。您可以使用静态类来保存这些方法。
以下是静态类的主要功能:
它们仅包含静态成员。
它们无法实例化。
他们被密封。
它们不能包含实例构造函数(C#编程指南)。
因此,创建静态类与创建仅包含静态成员和私有构造函数的类基本相同。私有构造函数可防止实例化该类。
使用静态类的优点是编译器可以检查以确保没有意外添加任何实例成员。编译器将保证不能创建此类的实例。
静态类是密封的,因此无法继承。它们不能从Object以外的任何类继承。静态类不能包含实例构造函数;但是,它们可以具有静态构造函数。有关更多信息,请参见静态构造函数(C#编程指南)。
当我们创建一个仅包含静态成员和私有构造函数的静态类时,唯一的原因是静态构造函数阻止了该类的实例化,因为我们无法继承静态类。访问该成员的唯一方法通过使用类名本身的静态类。尝试继承静态类不是一个好主意。