23

我试图弄清楚我的代码有什么问题。我有这个代码:

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 不像类那样实现结构?

4

7 回答 7

39

结构是隐式密封的

根据此链接

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;
}
于 2013-03-14T12:01:35.957 回答
4

struct 不支持继承,如果需要你必须使用类,见msdn

结构没有继承,就像类一样。一个结构不能从另一个结构或类继承,也不能是一个类的基础。然而,结构继承自基类 Object。结构体可以实现接口,它的实现方式与类完全一样。

于 2013-03-14T12:00:59.820 回答
4

.NET 中的值类型很奇怪,尽管它们是派生自名为ValueType. 对于每个值类型,都有一个堆对象类型,它的行为类似于派生自 的类对象ValueType,但值类型存储位置包含一个字节集合,这些字节要么表示原始值,要么是保存所有字节所需的字节的串联它的公共和私人领域。

由于值类型存储位置只保存表示其值所需的字节,并且既不保存类型信息,也不保存对将保存类型信息的对象的任何引用,因此使用值类型存储位置的代码必须确切地知道它是什么。

传统的继承要求对象保存有关其自身类型的信息,但没有规定值类型可以通过哪些方式来做到这一点。

对于 .NET 来说,通过一些特殊规则允许某些有限形式的值类型继承在概念上是可能的(并且有用的),例如BaseStructure变量只能保存 aBaseStructure而不能保存DerivedStructure. 可以定义一个StructureUser<T> where T:BaseStructure,并且这样的类或方法可以接受BaseStructure和使用这些成员的任何派生类——包括字段——这些成员对于基类是通用的。

不幸的是,很难为泛型定义规则,使其在允许的场景中表现一致,而又不破坏任何现有代码。

例如,在一个类Foo<T,U> where T:U中,总是可以将 a 存储T到一个 type 的变量中U,即使它U是一个值类型(即因为值类型是密封的,T并且U保证是相同的类型)。如果U可以是可继承的值类型并且T可以是派生的,则这样的保证将不成立。

考虑到与这种继承相关的困难,一个更有用的替代方法是提供一种安全(即使是有限的)方法,通过该方法属性可以暴露一个 byref 或一个 const-byref(一个 byref 是在参数使用时传递的东西限定符ref)。

这样的特性将消除字段和属性之间不可避免的语义区别,并且取决于它是如何实现的,即使在与类一起使用时也可以提供一些主要优势(例如,它可以允许有效混合不可变和可变类型)。

于 2013-03-14T19:33:24.473 回答
2

结构之间不允许继承,但结构可以实现接口。

于 2013-03-14T12:01:50.103 回答
2

其实有几个很好的理由:

  1. 结构没有“类型”

    ...除非它们被“装箱”成一个物体。

    object另一方面,在存储类型的普通 CLR 中有两个“标题”字段(以及一些 GC 和锁定信息)。添加它会改变结构的大小,并使它们的大小不可预测(因为某些运行时可能会选择以不同的方式添加该信息,例如,单声道运行时向其对象添加的“标题”信息比 .net 框架运行时更多,或者在过去最少这样做)

    当您尝试将结构分配给它实现的接口字段时,实际上会发生这种装箱。所以理论上这是可能的,但是你所有的结构都会被装箱,这对于性能来说真的很糟糕。

  2. 打字和固定大小

    为了说明为什么专门继承结构将是一个巨大的问题,让我们举一个简单的例子。

    考虑两个结构:struct MyBaseStruct { public int A; }和一个假设的 struct MyDerivedStruct : MyBaseStruct { public int B; }.

    现在当我打电话时会发生什么var array = new MyBaseStruct[10];?运行时会为此分配多少大小?

    分配array[0] = new MyDerivedStruct();会很麻烦,在 32 位系统上,它可能也会写入第一个第二个插槽。

    即使您尝试“收集”所有派生类型,它也不起作用,如果您加载另一个 dll,该 dll 定义了另一个从您的基本结构派生的结构,该怎么办?

我个人认为了解可能导致设计师首先做出决定的实际问题非常重要。但当然也可以只说“因为语言的设计者做到了!” “因为这就是 C# 语言规范所说的”:P

于 2019-06-07T03:02:48.657 回答
1

结构可以实现一个接口,但不能从另一个结构继承。因此,不能将结构成员声明为受保护的。

于 2013-03-14T12:05:27.697 回答
0

MSDN;

结构没有继承,就像类一样。一个结构不能从另一个结构或类继承,也不能是一个类的基础。然而,结构继承自基类 Object。结构体可以实现接口,它的实现方式与类完全一样。

但请记住,由于结构是值类型并且它们继承System.ValueType

于 2013-03-14T12:02:21.663 回答