我试着弄清楚我的代码有什么问题。 我有这段代码:
public struct MyStructA
{
public MyStructA(string str)
{
myString= str;
}
public string myString;
}
public struct MyStructB: MyStructA
{
public string myReversString;
}
我得到了这个错误:
Error at compile time: Type 'MyStructA' in interface list is not an interface
我不明白为什么? .net没有像类一样实现struct?
答案 0 :(得分:27)
结构被隐式密封
根据link:
C#中的每个结构,无论是用户定义的还是在.NET Framework中定义的,都是密封的 - 这意味着您无法继承它。结构被密封,因为它是一个值类型,所有值类型都是密封的。
结构体可以实现一个接口,因此可以在结构名称之后看到冒号后面的另一个类型名称。
在下面的示例中,当我们尝试定义一个继承自上面定义的结构的新结构时,我们会收到编译时错误。
public struct PersonName
{
public PersonName(string first, string last)
{
First = first;
Last = last;
}
public string First;
public string Last;
}
// Error at compile time: Type 'PersonName' in interface list is not an interface
public struct AngryPersonName : PersonName
{
public string AngryNickname;
}
答案 1 :(得分:4)
.NET中的值类型很奇怪,虽然它们是从名为ValueType
的特殊类派生的类,但它们已定义。对于每个值类型,都有一个堆对象类型,其行为类似于派生自ValueType
的类对象,但值类型存储位置包含一个字节集合,这些字节表示原始值或字节的串联必须拥有所有的公共和私人领域。
由于值类型存储位置只保存表示其值所需的字节,并且既不保存类型信息也不保存对包含类型信息的对象的任何引用,因此使用值类型存储位置的代码必须确切地知道它是什么
传统继承要求对象保存有关其自身类型的信息,但没有规定值类型可以通过哪些方式执行此操作。
.NET在概念上可以(并且有用)允许某些有限形式的值类型继承和一些特殊规则,这样虽然BaseStructure
变量只能容纳BaseStructure
和无法持有DerivedStructure
。可以定义一个StructureUser<T> where T:BaseStructure
,这样的类或方法可以接受BaseStructure
的任何派生,并使用那些成员 - 包括字段 - 这些是基类型共有的。
不幸的是,很难定义泛型规则,以便在允许的场景中表现一致,但不会破坏任何现有代码。
例如,在类Foo<T,U> where T:U
中,即使T
是值类型,也始终可以将U
存储到U
类型的变量中(即因为T
值类型已被密封,U
和U
保证相同类型)。如果T
可以是可继承的值类型而ref
可能是衍生品,则此类保证将无法保留。
鉴于与此类继承相关的困难,更有用的替代方法是提供一种安全(即使是有限的)方法,通过该方法,属性可以公开byref或const-byref(byref是在传递的时候传递的东西)参数使用{{1}}限定符。)
这样的特性将消除字段和属性之间不可避免的语义区别,并且取决于它的实现方式即使与类一起使用也可以提供一些主要优点(例如,它可以允许有效混合不可变类型和可变类型)。 / p>
答案 2 :(得分:3)
Struct不支持继承,如果您需要使用类,请参阅msdn
没有类的继承结构。结构 不能从另一个结构或类继承,它不能是基础 一堂课。但是,结构继承自基类Object。一个 struct可以实现接口,它与类完全相同 做。
答案 3 :(得分:1)
结构体之间不允许继承,但结构可以实现接口。
答案 4 :(得分:1)
结构可以实现一个接口,但它们不能从另一个结构继承。因此,不能将struct成员声明为protected。
答案 5 :(得分:0)
来自MSDN
;
结构没有继承,因为有类。结构 不能从另一个结构或类继承,它不能是基础 一堂课。但是,结构继承自基类Object。一个 struct可以实现接口,它与类完全相同 做。
但请记住,因为结构是值类型并且它们继承System.ValueType
答案 6 :(得分:0)
实际上有几个很好的理由:
结构没有“类型”
...除非将它们“装箱”到一个对象中。
另一方面,object
在普通CLR中有两个“标头”字段,用于存储类型(以及一些GC和锁定信息)。
添加它会改变结构的大小,并使结构的大小不可预测(因为某些运行时可能选择以不同的方式添加该信息,例如,与.net框架运行时相比,mono运行时向其对象添加更多的“标头”信息,或过去至少这样做的
当您尝试将结构分配给它实现的接口字段时,实际上发生了这种拳击。因此,从理论上讲是有可能的,但是随后您所有的结构都将被装箱,出于性能原因,这确实很糟糕。
键入和固定大小
为了说明为什么专门继承结构会是一个大问题,让我们举一个简单的例子。
考虑两个结构:struct MyBaseStruct { public int A; }
和一个假设
struct MyDerivedStruct : MyBaseStruct { public int B; }
。
现在,当我致电var array = new MyBaseStruct[10];
时会发生什么?运行时将为此分配多少大小?
分配array[0] = new MyDerivedStruct();
会很麻烦,在32位系统上,它可能可能写入第一个 AND 好吧。
即使您试图“收集”所有派生类型,它也行不通,如果加载另一个dll定义了另一个从您的基本结构派生的结构,该怎么办?
我个人觉得非常重要的一点是,首先要了解可能导致设计师做出决定的实际问题。 但是当然,也可以只说“因为该语言的设计者是这样做的!” 或“因为这就是C#语言规范所说的” :P >