我有几个类实际上不需要任何状态。从组织的角度来看,我想把他们放在层次结构中。

但是我似乎不能为静态类声明继承。

就像这样:

public static class Base
{
}

public static class Inherited : Base
{
}

不会起作用。

为什么语言的设计者们拒绝了这种可能性呢?


当前回答

你可以做的一个解决方法是不使用静态类,而是隐藏构造函数,这样类的静态成员是类外部唯一可访问的东西。结果是一个可继承的“静态”类:

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>();

不幸的是,由于“by-design”语言限制,我们无法做到:

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 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);
// ...

创建静态子对象的人不需要考虑序列化过程,只要他们了解平台或环境的序列化引擎上可能存在的任何限制。

静态变量(单例和其他形式的“全局变量”)经常出现在配置存储中。静态继承将允许这种职责分配在语法中清晰地表示,以匹配配置的层次结构。但是,正如我所指出的,如果实现基本的静态继承概念,就有可能产生大量的歧义。

我相信正确的设计选择是允许静态继承,但有特定的限制:

没有重写任何东西。子元素不能替换基底元素 属性、字段或方法…重载应该是可以的 只要有不同的签名允许编译器 整理出child和base。 只允许通用静态基,不能继承 非通用静态基。

您仍然可以通过通用引用MyStaticBase<ChildPayload>. somebasefield来更改相同的存储。但是您可能会感到气馁,因为必须指定泛型类型。而子引用会更干净:MyStaticChild.SomeBaseField。

我不是编译器的作者,所以我不确定我是否忽略了在编译器中实现这些限制的困难。也就是说,我坚信有限的静态继承需要信息空间,基本的答案是你不能因为糟糕的(或过于简单的)设计选择。

你可以做的一个解决方法是不使用静态类,而是隐藏构造函数,这样类的静态成员是类外部唯一可访问的东西。结果是一个可继承的“静态”类:

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>();

不幸的是,由于“by-design”语言限制,我们无法做到:

public static class TestClass<T>
{
    public static T Add(T x, T y)
    {
        return (dynamic)x + (dynamic)y;
    }
}

public static class TestClass : TestClass<double>
{
}

可以这样考虑:你通过类型名访问静态成员,就像这样:

MyStaticType.MyStaticMember();

如果你要从这个类继承,你必须通过新的类型名来访问它:

MyNewType.MyStaticMember();

因此,在代码中使用时,新项与原始项没有关系。没有办法利用任何继承关系来处理多态性之类的事情。

也许您只是想扩展原始类中的一些项。在这种情况下,没有什么可以阻止您在一个全新的类型中使用原始类型的成员。

也许您希望向现有静态类型添加方法。您已经可以通过扩展方法做到这一点。

也许您希望能够在运行时将静态类型传递给函数,并调用该类型的方法,而不需要确切地知道该方法的功能。在这种情况下,您可以使用接口。

所以,最终你不会从继承静态类中获得任何东西。