首页 文章

为什么我不能继承静态类?

提问于
浏览
202

我有几个不需要任何州的课程 . 从组织的角度来看,我想把它们放到层次结构中 .

但似乎我无法为静态类声明继承 .

像这样的东西:

public static class Base
{
}

public static class Inherited : Base
{
}

不管用 .

为什么语言的设计者会关闭这种可能性?

11 回答

  • 1

    来自here的引文:

    这实际上是设计的 . 似乎没有充分的理由继承静态类 . 它有公共静态成员,您始终可以通过类名本身访问它们 . 我看到继承静态内容的唯一原因是糟糕的,例如保存几个字符的输入 . 可能有理由考虑将静态成员直接引入范围的机制(事实上我们将在Orcas产品周期之后考虑这一点),但静态类继承不是要走的路:它是错误的使用机制,并且有效仅适用于碰巧驻留在静态类中的静态成员 . (Mads Torgersen,C#语言PM)

    来自channel9的其他意见

    .NET中的继承仅适用于实例库 . 静态方法是在类型级别上定义的,而不是在实例级别上定义的 . 这就是为什么重写不适用于静态方法/属性/事件...静态方法只在内存中保存一次 . 没有为它们创建的虚拟表等 . 如果在.NET中调用实例方法,则始终为其提供当前实例 . 这是.NET运行时隐藏的,但它确实发生了 . 每个实例方法都将第一个参数作为运行该方法的对象的指针(引用) . 静态方法不会发生这种情况(因为它们是在类型级别定义的) . 编译器应该如何决定选择要调用的方法? (littleguru)

    作为一个有 Value 的想法,littleguru对于这个问题有一个部分"workaround":Singleton模式 .

  • 2

    您不能继承静态类的主要原因是它们是抽象的和密封的(这也可以防止创建它们的任何实例) .

    所以这:

    static class Foo { }
    

    汇编到这个IL:

    .class private abstract auto ansi sealed beforefieldinit Foo
      extends [mscorlib]System.Object
     {
     }
    
  • -1

    这样考虑一下:通过类型名称访问静态成员,如下所示:

    MyStaticType.MyStaticMember();
    

    如果您继承该类,则必须通过新类型名称访问它:

    MyNewType.MyStaticMember();
    

    因此,当在代码中使用时,新项目与原始项目没有关系 . 对于像多态这样的东西,没有办法利用任何继承关系 .

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

    也许您想要将方法添加到现有的静态类型中 . 您可以通过扩展方法完成此操作 .

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

    所以,最后你并没有从继承静态类中获得任何东西 .

  • 22

    您希望通过使用类层次结构实现的目标只需通过命名空间即可实现 . 因此,支持namespapces的语言(如C#)将不会使用实现静态类的类层次结构 . 由于您无法实例化任何类,因此您只需要通过使用命名空间获得的类定义的分层组织

  • 70

    您可以使用组合...这将允许您从静态类型访问类对象 . 但仍然无法实现接口或抽象类

  • 1

    虽然您可以通过继承的类名访问“继承的”静态成员,但静态成员并不是真正继承的 . 这部分是为什么它们不能是虚拟的或抽象的,也不能被覆盖 . 在您的示例中,如果您声明了Base.Method(),则编译器无论如何都会将对Inherited.Method()的调用映射回Base.Method() . 您也可以明确地调用Base.Method() . 您可以编写一个小测试并使用Reflector查看结果 .

    那么......如果你不能继承静态成员,并且静态类只能包含静态成员,那么继承静态类会有什么好处呢?

  • 3

    嗯...如果你只是用静态方法填充非静态类会有什么不同吗?

  • 163

    您可以做的解决方法不是使用静态类,而是隐藏构造函数,因此类静态成员是唯一可访问的课外 . 结果是一个可继承的“静态”类本质上:

    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>
    {
    }
    
  • 3

    你可以做一些看似静态继承的事情 .

    这是诀窍:

    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 关键字 . 但是这种方法有助于支持与静态继承非常相似的东西 .

    附:我们使用它来创建编译查询,这实际上可以用ConcurrentDictionary替换,但是一个静态只读字段及其线程安全性已经足够了 .

  • 1

    静态类和类成员用于创建可在不创建类实例的情况下访问的数据和函数 . 静态类成员可用于分离独立于任何对象标识的数据和行为:无论对象发生什么,数据和函数都不会更改 . 当类中没有依赖于对象标识的数据或行为时,可以使用静态类 .

    可以将类声明为static,这表示它只包含静态成员 . 无法使用new关键字创建静态类的实例 . 当加载包含该类的程序或命名空间时,.NET Framework公共语言运行库(CLR)会自动加载静态类 .

    使用静态类来包含与特定对象无关的方法 . 例如,创建一组不对实例数据起作用且与代码中的特定对象无关的方法是一种常见的要求 . 您可以使用静态类来保存这些方法 .

    以下是静态类的主要特性:

    • 它们只包含静态成员 .

    • 他们无法实例化 .

    • 他们是密封的 .

    • 它们不能包含实例构造函数(C#编程指南) .

    因此,创建静态类与创建仅包含静态成员和私有构造函数的类基本相同 . 私有构造函数可以防止实例化类 .

    使用静态类的优点是编译器可以检查以确保不会意外添加实例成员 . 编译器将保证无法创建此类的实例 .

    静态类是密封的,因此不能继承 . 它们不能从除Object之外的任何类继承 . 静态类不能包含实例构造函数;但是,它们可以有一个静态构造函数 . 有关更多信息,请参阅静态构造函数(C#编程指南) .

  • 0

    当我们创建一个只包含静态成员和私有构造函数的静态类时 . 唯一的原因是静态构造函数阻止了类的实例化,因为我们无法继承静态类 . 访问成员的唯一方法是静态类通过使用类名本身 . 尝试继承静态类不是一个好主意 .

相关问题