为什么C#结构不能被继承?

smw*_*dia 85 .net c#

我正在通过C#由Jeffery Richter阅读CLR,它说结构是一种值类型,不能继承.

有任何技术或哲学原因吗?

Jes*_*kan 86

编辑:显然,这篇文章存在严重的编辑问题.见评论部分.

两者兼而有之.

从哲学上讲,它可以解决 - 有些类是面向对象编程的"真正"构建块,并且有一些结构,它们是用于存储的轻量级数据类型,但允许类似对象的方法调用以获得熟悉和方便.

从技术上讲,作为"值类型"意味着整个结构 - 所有内容 - (通常)存储在您拥有变量或该类型成员的任何地方.作为局部变量或函数参数,这意味着在堆栈上.对于成员变量,这意味着完全存储为对象的一部分.

作为继承是一个问题的(主要)示例,如果允许结构具有包含更多成员的子类型,请考虑如何在较低级别影响存储.存储该结构类型的任何东西都会根据它最终包含的子类型占用可变数量的内存,这将是一个分配的噩梦.给定类的对象在编译时不再具有常量的已知大小,并且对于任何方法调用的堆栈帧都是如此.对于具有在堆上分配存储的对象而言,这不会发生,而是对堆栈上或其他对象内的存储具有恒定大小的引用.

这只是一个直观的,高级别的解释 - 查看扩展和更精确信息的评论和其他答案.

  • @smwikipedia你应该参考Eric Lippert的文章[Stack是一个实现细节](http://blogs.msdn.com/b/ericlippert/archive/2009/04/27/the-stack-is-an-implementation- detail.aspx) (4认同)
  • 我可以看到一些实质性的好处,即允许定义“派生结构”,该结构将支持双向标识保留到其派生类型的转换。“派生的结构类型”将不允许定义任何新字段,并且对它可以做什么有一些限制,但在某些情况下仍然有用。如果愿意,请参见http://stackoverflow.com/a/11073235/363751。 (2认同)
  • 请注意,C#`struct`s在概念上与C++对象相同,并且在C++中继承是可能的.但是,您提到的问题是通过[对象切片](http://stackoverflow.com/questions/274626/what-is-object-slicing)解决的,这是非常不直观的_(并且基本上是一个实现细节泄漏到语言)_ (2认同)
  • 仅仅因为它存储在堆栈上是没有借口的-CLR具有*托管*堆栈,并且CLR在运行时知道结构的确切类型;没有理由不应该相应地分配确切的空间量。 (2认同)
  • @BrainSlugs83:如果你不改变变量,这是可以的。但如果是这样的情况会发生什么呢:`ParentS x = GetParentOrChildRandomly()`,其中`ParentS`占用24B,而`ChildS : ParentS`占用32B?运行时无法事先知道堆栈大小。另外,想象一下这种情况发生在堆中对象的字段上。GC 必须找到一种方法来添加(或删除)堆中现有对象(可能已经压缩)的空间。 (2认同)

Dar*_*rov 37

因为它是.NET中表示结构的方式.它们是值类型,值类型没有允许继承的方法表指针.

  • 有人可能会补充:它们没有方法表指针的原因是因为值类型被设计为尽可能轻量级. (18认同)
  • 除了结构*可以*实现接口,并且方法表指针用于调用它们... (12认同)
  • 结构体可以通过多种方式在不需要每个实例类型信息的情况下有效地支持继承:(1) 通过说`FooStruct:BarStruct` 的*唯一* 效果将是约束到`BarStruct` 的泛型类型将能够直接访问该类型的成员(*包括字段*);(2) 通过说任何类型`FooStruct:BarStruct` 必须以契约方式绑定使用其继承的字段,通过复制现有`FooStruct` 的继承字段形成的`BarStruct` 必须是有效的`BarStruct` , 和... (2认同)

Rob*_*son 16

您可以找到SO问题的答案为什么.NET值类型被密封?相关.在其中,@ logicnp指的是ECMA 335,其中指出:

8.9.10值类型继承

  • [...]
  • 将密封以避免处理价值切片的并发症.
  • 此处指定的限制性规则允许更有效的实施,而不会严重损害功能.

  • 在"没有严重损害功能"的情况下,它们显然意味着"严重损害功能". (2认同)