为什么值类型继承自引用类型?

12 c# inheritance

我有两个问题:

  1. 我们知道所有类型派生自Object哪个是引用类型.我的问题是为什么int- 这是一种类型 - 继承自引用类型Object?这可能吗?

  2. 如果int是派生的Object,为什么我们需要在传递int给期望object作为参数的函数时使用?通常使用引用,当您需要将派生类型的对象作为参数传递给函数期望基类型的对象时,您不需要执行任何其他操作.为何选择这里?

对我来说,这种情况似乎是这种类型层次结构的设计问题.

PS.我找到了这个相关的问题,但那里的答案没有给出任何现实的见解 - 只是抽象地谈论盒子.

Hei*_*nzi 5

我们需要注意不要在这里混淆概念。

首先,有子类型int是 的子类型object。子类型基本上意味着由超类型保证的契约(例如“有一个方法 ToString,它返回一个合适的字符串表示。”)也为子类型提供保证。

然后是 C# 中继承。在 C# 中,继承

  1. 创建一个亚型通过确保由超型提供的接口也是在亚型可用和

  2. 提供默认实现,即,如果您不覆盖方法,您将获得超类型的实现。这基本上是一个方便的功能。

C# 中的接口实现将是另一种子类型机制的示例,它提供 1 但不提供 2。)

这基本上就是全部。子类型或继承都不能保证内存布局、值/引用类型语义等。这些概念是正交的。


“但那是不对的,”你可能会说。object合同的一部分是‘引用类型语义’。” 这就是需要拳击的地方。只要值类型的编译时类型是引用类型(即objectValueType或接口),它就会模拟引用类型语义。


Yuv*_*kov 3

我们知道所有类型都派生自 Object。这是引用类型。我的问题是为什么 int (值类型)继承自引用类型 Object?这可能吗?

System.Int32派生自System.ValueType,C# 中的所有结构也是如此。编译器允许此继承链,这与禁止您以任何其他struct类型进行继承的机制相同。公共语言运行时 (CLR) 对于派生自System.ValueType. System.ValueType本身不是值类型,它是构成所有结构的基类的引用类型。尽管存在这种继承层次结构,但它不需要保证对象在内存中的布局方式。

为什么我们在将 int 传递给需要对象作为参数的函数时需要装箱?通常,当您需要将派生类型的对象作为参数传递给需要基类型对象的函数时,使用引用时,您不需要执行任何其他操作。为什么要在这里装箱?

因为虽然anystruct最终派生自object,但它实际上被运行时区别对待。所有结构都被视为数据块,它们没有方法表指针或同步块索引,而 .NET 中的每个引用类型都具有这些指针或同步块索引。这就是为什么传递给接受 an 的方法的任何值类型都object必须装箱,因为需要向其中添加附加数据才能真正成为完全限定的object类型。值类型不仅在作为object类型传递时被装箱,例如,当您调用struct因实现接口而添加到您的方法时,它们也会被装箱。该值类型需要装箱,以便获取指向它需要调用的方法的实际方法表指针。

你可以通过一个小例子来了解它:

void Main()
{
    IFoo m = new M();
    m.X();
}

public struct M : IFoo
{
    public void X() { }
}

public interface IFoo 
{
    void X();
}
Run Code Online (Sandbox Code Playgroud)

将产生以下 IL(在 Release 模式下编译):

IL_0000:  ldloca.s    00 
IL_0002:  initobj     UserQuery.M
IL_0008:  ldloc.0     
IL_0009:  box         UserQuery.M
IL_000E:  callvirt    UserQuery+IFoo.X
IL_0013:  ret         
Run Code Online (Sandbox Code Playgroud)