Artyom Asked:2020-10-21 21:49:47 +0000 UTC2020-10-21 21:49:47 +0000 UTC 2020-10-21 21:49:47 +0000 UTC 为什么禁止从值类型继承? 772 为什么禁止从值类型继承,比如struct?什么struct sealed是明确的 :) 但他们为什么要这样做sealed? c# 1 个回答 Voted Best Answer VladD 2020-10-21T21:59:36Z2020-10-21T21:59:36Z 问题是这样的。假设允许它从结构继承。 考虑这段代码: class C1 { int x; } class C2 : C1 { int y; public override string ToString() { return y.ToString(); } } 你可以这样写:C1 c = new C2();然后调用c.ToString();. 由于c只是引用数据,所以调用没有问题。这是一个标准特性,引用类型的基本多态行为。 现在想象一个类似的情况: struct S1 { int x; } struct S2 : S1 { int y; public override string ToString() { return y.ToString(); } } S1 s = new S2(); 会有什么s?出于效率的原因,结构按原样存储在内存中,即只是一组字段,而不是对它们的引用。这意味着s分配给 pod 的字节数与它占用的字节数一样多,并且根本没有空间S1容纳该字段!y在这种情况下调用应该返回什么s.ToString()? 将派生类型参数传递给需要基类型参数的函数时,也会出现类似的问题。 这个问题称为切片,与许多编程语言的设计有关。例如,它存在于 C++ 中。C# 中的解决方案是拒绝继承结构:允许在继承中破坏多态性是一个坏主意。使用此解决方案,排除了 C# 中的切片。 其他语言解决问题的方式不同。例如,在 C++ 中,对象的真实类型s将简单地为S1,而不是S2,并且y将简单地丢失。C# 语言的创建者认为这种行为不直观,会导致问题和错误,因此他们选择了一条不同的道路。如果你需要继承,在 C# 中你需要使用类,或者去组合。 如果结构以与类完全相同的方式存储,问题就可以解决:不是值,而是对它的引用。同时,像赋值这样的操作必须复制一个值而不是一个引用,以保存语义。但是这种方法,虽然它允许结构的继承,但会大大降低它们的效率:由于不必要的间接访问,结构的每个操作都会变得更慢,而且一般情况下结构的分配会被推出堆栈进入堆。 该语言的架构师用结构的多态性来换取它们的效率。
问题是这样的。假设允许它从结构继承。
考虑这段代码:
你可以这样写:
C1 c = new C2();然后调用c.ToString();. 由于c只是引用数据,所以调用没有问题。这是一个标准特性,引用类型的基本多态行为。现在想象一个类似的情况:
会有什么
s?出于效率的原因,结构按原样存储在内存中,即只是一组字段,而不是对它们的引用。这意味着s分配给 pod 的字节数与它占用的字节数一样多,并且根本没有空间S1容纳该字段!y在这种情况下调用应该返回什么s.ToString()?将派生类型参数传递给需要基类型参数的函数时,也会出现类似的问题。
这个问题称为切片,与许多编程语言的设计有关。例如,它存在于 C++ 中。C# 中的解决方案是拒绝继承结构:允许在继承中破坏多态性是一个坏主意。使用此解决方案,排除了 C# 中的切片。
其他语言解决问题的方式不同。例如,在 C++ 中,对象的真实类型
s将简单地为S1,而不是S2,并且y将简单地丢失。C# 语言的创建者认为这种行为不直观,会导致问题和错误,因此他们选择了一条不同的道路。如果你需要继承,在 C# 中你需要使用类,或者去组合。如果结构以与类完全相同的方式存储,问题就可以解决:不是值,而是对它的引用。同时,像赋值这样的操作必须复制一个值而不是一个引用,以保存语义。但是这种方法,虽然它允许结构的继承,但会大大降低它们的效率:由于不必要的间接访问,结构的每个操作都会变得更慢,而且一般情况下结构的分配会被推出堆栈进入堆。
该语言的架构师用结构的多态性来换取它们的效率。