【问题标题】:What does really happen when you do GetType()?执行 GetType() 时真正发生了什么?
【发布时间】:2010-07-21 18:45:03
【问题描述】:

众所周知,C# 对象有一个指向其类型的指针,因此当您调用 GetType() 时,它会检查该指针并返回对象的真实类型。但如果我这样做:

A objA = new A();
object obj = (object)objA;
if (obj.GetType() == typeof(object)) ; // this is true

但是object obj = (object)objA; 这里发生了什么?它是否创建某种引用对象,引用objA,但有一个指向object 的类型指针,或者它是一个全新的对象,恰好指向与@ 相同的属性、字段等987654326@?当然,您现在可以访问这两个对象,它们将具有不同的类型,但指向相同的数据。它是如何工作的?

另一个问题是:GetType() 是否保证返回对象的实际类型?例如,假设有一个签名为void Method(object sender) 的方法,我们将A 类型的对象作为参数传递。 sender.GetType() 会返回类型A 还是object?为什么?

其他棘手的事情是您可以执行(A)obj 并且它会起作用。既然 obj 曾经是 A 类型,那么 CLR 怎么办?

如果有人能比“C# via CLR”更清楚地分解它,我会很高兴。

更新。我的错,应该在发布问题之前运行代码。所以,如果GetType() 真的总是返回真实类型,那么所有其他问题也会变得清晰。

【问题讨论】:

  • 您的问题是基于一个完全错误的前提。标有“这是真的”的那行不是真的。如果您不相信我,请尝试编写一个实际编译和运行的小程序。 GetType() 总是返回对象的实际运行时类型。您所有的问题都基于编译时类型与它有关的错误假设。它没有。
  • @Eric,嗯,你是对的,这就是我一直认为的,因为项目中一些行为不同的代码而分心,我的错。

标签: c#


【解决方案1】:

众所周知,C# 对象有一个指向其类型的指针,因此当您调用 GetType() 时,它会检查该指针并返回对象的真实类型。

正确。

如果我这样做:

class A {}
class P
{
    public static void Main()
    {
        A objA = new A(); 
        object obj = (object)objA; 
        bool b = obj.GetType() == typeof(object) ; // this is true
    }
}

不,那是错误的。试试看!

但是这里发生了什么object obj = (object)objA;?

objA 中的引用被复制到变量 obj。 (除非 A 是值类型,在这种情况下它被装箱,并且对该框的引用被复制到 obj。)

它是否创建了某种引用对象,它引用了 objA,但有一个指向对象的类型指针,或者它是一个全新的对象,它恰好指向与 objA 相同的属性、字段等?

两者都不是。它复制参考,期间。完全没有变化。

当然,您现在可以访问这两个对象,它们将具有不同的类型,但指向相同的数据。它是如何工作的?

它没有。这个问题是基于一个错误的假设。他们不会有不同的类型。它们是相同的参考。 变量有不同的类型,但这无关紧要;您不是在询问变量的类型,而是询问变量的 contents 类型。

GetType() 是否保证返回对象的实际类型?

出于您的目的,是的。有一些涉及 COM 互操作的模糊情况,但它没有。

例如,假设有一个签名为 void Method(object sender) 的方法,我们将 A 类型的对象作为参数传递。 sender.GetType() 会返回类型 A 还是对象?

类型 A。

为什么?

因为那是对象的类型。

其他棘手的事情是您可以执行 (A)obj 并且它会起作用。既然 obj 曾经是 A 类型,CLR 怎么办?

C# 编译器生成一个 castclass 指令。 castclass 指令执行运行时检查以验证对象引用是否实现了所需的类型。如果没有,则 CLR 会引发异常。

【讨论】:

  • Eric,出于兴趣,我如何区分变量的运行时类型和它所指的对象类型?类型系统没有两个级别/阶段吗?即编译时间类型(用于产生这样的错误: ((object)mystring).Substring() ),以及用于反射的运行时类型(GetType())。当编译失败时,这是因为编译时类型检查(即根本不是运行时类型检查,因此本身不使用变量或实例类型)。变量自己的类型(而不是它所指事物的类型)是否仅在编译时体现?
  • 对不起,当我说区分时,我应该说“在运行时通过反射区分”。
  • @Andrew:C# 编译器在编译时和 CLR 验证程序在运行时知道变量的类型。验证器通过确保没有变量被赋予与其类型不兼容的值来验证代码是否可验证类型安全。如果您的问题是“我可以使用反射来反映局部变量的类型吗”,不可以,因为局部变量不会通过反射暴露。您当然可以考虑字段或形式参数的类型。
  • 局部变量通过反射暴露出来,但是没有任何方法可以将实际变量映射到 LocalVariableInfo。
  • @Jb:你当然是对的,我忘记了。但是,由于它们没有按名称在元数据中公开,因此没有那么有用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-13
  • 2017-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多