【问题标题】:How can a value type implement a ref type值类型如何实现 ref 类型
【发布时间】:2013-05-24 22:07:46
【问题描述】:

我遇到了一个场景,其中一个值类型正在实现 ref。输入。

只是想知道这怎么可能(幕后发生了什么?)

结构是值类型,接口是引用。类型,但结构可以实现接口而不会出现任何错误...

有什么想法吗? 提前致谢

【问题讨论】:

    标签: c# oop


    【解决方案1】:

    实际上,它同时以两种不同的方式进行。

    首先,任何值类型都可以装箱到引用类型的对象实例中。这个盒子是由运行时按需发明的,它将以您期望的方式实现接口 - 即,盒子将实现值类型实现的任何接口。

    但是,CLI 也允许“受限调用”。受约束的调用将虚拟调用转换为静态调用,但仅适用于值类型通过覆盖或接口实现的方式实现实例方法的场景(否则它由 JIT 作为虚拟调用实现)。特别是泛型广泛使用了受约束的调用(受约束的操作码是与泛型同时添加的,正是出于这个原因)。

    【讨论】:

    • +1,你是对的。我提供了示例,但没有解释原因。
    • @Gjeltema 我希望能激励你添加更多细节,而不是删除你的答案:(
    • 好吧,我本可以添加更多细节 - 但你已经回答过了,所以似乎没有多大意义。 :) 别担心 - 我会活到另一天回答。
    • @Gjeltema:我很想看看你的例子。
    • @PieterGeerkens 没什么特别的,只是 int 之类的 (msdn.microsoft.com/en-us/library/system.int32.aspx)。不过,Marc 的回复实际上回答了这个问题。
    【解决方案2】:

    接口不是引用类型,它只是关于如何实现类型的约定。

    接口类型的变量必须是引用,因为实现接口的类型可以是引用类型。接口类型的变量必须能够保存引用类型或值类型,因为两者都可以实现接口。可以将值类型装箱以便获得引用,但不能将引用类型“扁平化”为值。

    【讨论】:

    • 这里的 flattened 是什么意思.. ?
    • @KenKin: 嗯……扁平化了……它应该描述一个引用类型如何变成一个值类型,但它没有任何确切的含义,因为那是不可能的.
    • 哦..谢谢。我仍然很难理解。由于我不确定 flattened 是指转换或装箱,还是其中一种并包括任何其他方式?
    • @KenKin:最接近真实的东西是拆箱,但你不能拆箱不是首先通过装箱创建的东西。
    • 啊..是真的。我的英语很差,经常不能掌握一些特殊的描述。非常感谢您的澄清。
    【解决方案3】:

    虽然我们都使用 Type 这个词来指代接口,事实上,即使是 MSDN 文档也将接口描述为 reference Types,但接口与任何其他引用类型的意义不同或任何值类型。在非常真实的意义上,它根本不是一种类型。它是类型必须包含的行为(一组方法、属性和事件)的约定,该类型必须通过声明来实现该接口。

    public interface ITestInterface { }
    public class MyClass:ITestInterface { } 
    
    ITestInterface m = new MyClass() as ITestInterface;
    var t = m.GetType();
    

    您会看到,即使变量m 被声明为ITestInterface 类型,类型变量t 仍然是MyClass

    因此,尽管出于历史原因,我们使用 type 这个词来应用于接口,但接口的“类型”与具体对象的类型(即类或结构的实例。

    引用 Don Box 的 Essential .Net

    CLR 处理对象和接口类型的方式与其不同 前辈(C++ 和 COM)。在 C++ 和 COM 中,给定的具体类型 每个基本类型或支持的接口都有一个方法表。在 相反,CLR 中给定的具体类型只有一个方法 桌子。通过推断,基于 CLR 的对象只有一个类型句柄。 这与 C++ 和 COM 形成鲜明对比,在 C++ 和 COM 中,对象将 通常每个基本类型或接口都有一个 vptr。为此原因, CLR 的 castclass 不会在 与 C++ 的 dynamic_cast 或 COM 的 Query-Interface 相同。

    读到这里很清楚,接口本身永远不可能有 vptr 表或 CORINFO_CLASS_STRUCT,因为只有真正的具体对象(引用和值类型)才能拥有。此结构由 CLR 为执行代码在运行时加载的每个类型创建和维护。同样,来自 Essential .Net

    CORINFO_CLASS_STRUCT 包含指向两个表的指针,这些表描述 该类型支持的所有接口。 isinstcastclass [CLR] 操作码使用这些表之一来确定一个类型是否支持 给定的接口。这些表中的第二个是接口偏移量 CLR 在分派进行的虚拟方法调用时使用的表 反对基于接口的对象引用。

    从这些引用中可以清楚地看出,接口与引用类型(类)或值类型(结构)根本不同。在 .Net 中实例化或使用的每个对象(引用类型)或值类型都必须是类或结构的具体实例。并且 CLR 加载的每个对象或结构都具有对为该类或结构的具体类型创建的单个 CORINFO_CLASS_STRUCT 的引用。接口是类型的类别,其定义是为了保证声明为该类别的任何类或结构(声明为实现该接口)必须包含每个声明的成员的类型成员(方法、属性、事件等)接口定义。

    【讨论】:

      【解决方案4】:

      从某种意义上说,接口不是类型和结构!接口本身并不存在;所以它们既不是引用类型也不是值类型。您可以将 null 分配给引用。但是,如果实现者类型是值类型,那么当您将该类型的变量分配给另一种类型时,它的行为就像值类型一样。因此它的行为类似于引用类型的引用类型。

      类和结构是数据(代码)的类型,但接口是类型的类型。它们可用于对其他类型进行分类。他们强迫其他类型遵循协议,仅此而已。它们只是一个布局,一个定义,一个契约;不是现有的东西。

      【讨论】:

      • 接口绝对是类型。 List<T>IList<T> 类型的变量之间存在差异。后者可以引用与前者相同类型的实例,但引用(作为该变量)仍将被键入为接口。
      • 我没有说它们不是类型。并且接口的基本类型不是 System.Object 所以:“接口不是类和结构的某种意义上的类型”; “类和结构是数据(代码)的类型,但接口是类型的类型”。
      猜你喜欢
      • 1970-01-01
      • 2013-09-12
      • 2018-10-29
      • 1970-01-01
      • 2015-07-18
      • 2023-03-08
      • 1970-01-01
      • 1970-01-01
      • 2013-11-11
      相关资源
      最近更新 更多