2009-04-21 78 views
182

我有几个类并不真的需要任何状态。从组织的角度来看,我希望把它们放在层次结构中。为什么我不能继承静态类?

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

类似的东西:

public static class Base 
{ 
} 

public static class Inherited : Base 
{ 
} 

将无法​​正常工作。

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

+0

[哪有静态类的可能的复制从一个对象派生?](http://stackoverflow.com/questions/556203/how-can-a-static-class-derive-from-an-object) – 2015-11-26 13:48:23

回答

148

引文从here

这实际上是由设计。似乎没有理由继承静态类。它具有公共静态成员,您可以随时通过类名称本身进行访问。 我见过的继承静态东西的唯一理由是坏的,比如保存了几个字符的输入。

可能有理由考虑使静态成员直接进入范围的机制(实际上我们会在Orcas产品周期之后考虑这一点),但是静态类继承并不是一种可行的方法:它是错误的机制使用,并且仅适用于恰好驻留在静态类中的静态成员。

(的Mads托格森,C#语言PM)从channel9

继承在.NET

其它意见只对实例的基础工作。静态方法在类型级别上定义,而不是在实例级别上定义。这就是为什么覆盖不能用于静态方法/属性/事件...

静态方法只在内存中保留一次。没有为他们创建的虚拟表等。

如果您在.NET中调用实例方法,则始终将其指定为当前实例。这是由.NET运行时隐藏的,但它发生了。 每个实例方法的第一个参数都有一个指向运行该方法的对象的指针(引用)。这不会发生在静态方法(因为它们是在类型级别上定义的)。编译器应该如何决定选择要调用的方法?

(littleguru)

而作为一个有价值的想法,littleguru有针对此问题的部分 “解决办法”:在Singleton模式。

+1

至于你的第一个引用,你可以将一个实例类作为基类,然后使用它的公共成员。 – 2009-05-15 13:13:21

+62

Torgersen一方缺乏想象力,真的。我有一个很好的理由想要做到这一点:) – Thorarin 2010-01-19 14:31:04

+2

你会分享它吗? – boj 2011-08-15 11:24:34

1

嗯......如果你只是有非静态类填充静态方法会有很大的不同...?

+2

这是留给我的。我这样做。我不喜欢它。 – User 2009-04-21 19:42:55

+0

我也是这样做的,但出于某种原因,当你知道你永远不会实例化对象时,它不会感觉到美学。尽管事实上没有任何材料成本,但我总是为这样的细节而痛苦。 – gdbj 2015-02-08 18:51:05

20

想想这样说:你通过类型名称来访问静态成员,像这样:

MyStaticType.MyStaticMember(); 

是你从该类继承,就必须通过新的类型名称来访问它:

MyNewType.MyStaticMember(); 

因此,当在代码中使用新项目时与原始项目没有关系。没有办法像多态性那样利用任何继承关系。

也许你认为你只是想扩展原始类中的一些项目。在这种情况下,没有什么能够阻止您仅仅使用全新类型的原件成员。

也许你想添加方法到现有的静态类型。你可以通过扩展方法来做到这一点。

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

所以,最终你并没有真正从继承静态类中获得任何东西。

61

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

所以这个:

static class Foo { } 

编译此IL:

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

要通过使用类层次结构可以通过仅仅被命名空间实现实现什么。所以支持名称空间的语言(如C#)将不能使用静态类的类层次结构。由于您无法实例化任何类,因此您只需要使用命名空间即可获得的类定义的层次结构组织

2

尽管您可以通过继承的类名访问“继承的”静态成员,但静态成员并没有真正的继承。这部分原因在于它们不能是虚拟的或抽象的,不能被覆盖。在您的示例中,如果您声明了Base.Method(),则编译器将调用Inherited.Method()映射回Base.Method()。你也可以直接调用Base.Method()。您可以编写一个小测试并使用Reflector查看结果。

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

3

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

0

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

一个类可以被声明为静态,这表明它只包含静态成员。使用new关键字创建静态类的实例是不可能的。当包含类的程序或名称空间被加载时,静态类将由.NET Framework公共语言运行库(CLR)自动加载。

使用静态类来包含与特定对象无关的方法。例如,创建一组方法不会影响实例数据,并且不会与代码中的特定对象关联,这是一个常见要求。你可以使用静态类来保存这些方法。

下面是一个静态类的主要特点:

  1. 它们只包含静态成员。

  2. 它们不能被实例化。

  3. 它们是密封的。

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

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

使用静态类的好处是编译器可以检查以确保没有实例成员被意外添加。编译器将保证不能创建这个类的实例。

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

-1

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

1

你可以做一些看起来像静态继承的东西。

这是使用方法:

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替代,但是它的线程安全的静态只读字段足够好。

0

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

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