CLR如何知道装箱对象的类型?

15

值类型被装箱后,会被放置在一个不带类型的引用对象中。 那么是什么导致了这里的无效转换异常?

long l = 1;
object obj = (object)l;
double d = (double)obj;
2个回答

18

不,它没有放置在一个未类型化的对象中。对于每种值类型,在CLR中都有一个装箱的引用类型。所以你将会得到类似这样的结果

No, 它不是放在一个未类型化的对象中. 对于每个值类型,在 CLR 中都有一个装箱的引用类型。因此,你会得到 类似下面的内容

public class BoxedInt32 // Not the actual name
{
    private readonly int value;
    public BoxedInt32(int value)
    {
        this.value = value;
    }
}

在C#中直接无法访问该封装类型,虽然在C++/CLI中可以。显然,它知道原始类型。因此,在C#中,您必须具有object的编译时类型才能使用该变量,但这并不意味着这就是对象的实际类型。

有关更多详细信息,请参见ECMA CLI规范CLR via C#


有趣,谢谢Jon。Wagner的Effective C#指出:“装箱将值类型放置在未经类型化的引用对象中”。我相当确定它还说过类似于装箱对象不包含任何类型元数据的话,尽管我现在找不到那个特定的引用。正是在阅读那本书时,这个问题才浮现在我脑海中。 - fearofawhackplanet
@fearofawhackplanet:我不想替Bill解释他具体指的是什么- 但盒子对象绝对 知道 它的原始类型,包括枚举。 (将枚举值装箱并直接使用ToString,无需取消装箱即可证明 :) - Jon Skeet
1
我认为一个很好的演示是这样的。long l = 40L; object o = (object)l; Console.WriteLine(o.GetType()); 在这种情况下,屏幕上打印出了System.Int64。即使o是一个对象,底层类型仍然是long。 - Anthony Pegram

6

Jon Skeet的回答涵盖了为什么会出现这种情况;至于如何避免它,以下是你需要做的:

long l = 1;
object obj = (object)l;
double d = (double)(long)obj;

双重转换的原因是这样的:当.NET对变量进行拆箱时,它只知道如何将其拆箱为其原来的类型(在您的示例中为long)。一旦您对其进行了拆箱并且拥有了一个适当的long基元,您就可以将其转换为double或任何其他可从long转换的类型。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接