object.tostring()如何在盒装值类型上工作


class Program {
    static void Main(string[] args) {
        Int32 i = 123;
        Double d = 123.456;
        FunPrint(i);
        FunPrint(d);
    }
    static void FunPrint(object obj) {
        Console.WriteLine(obj);
    }
}

我对该示例的理解是FunPrint()首先创建一个新对象,并根据所传递的ValueType的值(在这种情况下为Int32)来构建它。其次, Object.ToString()被调用并正确显示valueType特定于特定于字符串格式。

值类型不包含虚拟函数,因此...

我不明白的是Object如何知道它在内部拥有哪种类型以进行适当的字符串格式。

调用函数框在调用 FunPrint之前先进行参数。

值类型不包含虚拟函数,所以...

实际上他们可以。您可以从值类型实现接口。您只是无法从一个限制覆盖水平的一个。

但是要调用虚拟函数虚拟函数,您需要装箱值类型。

该机制在这里同样适用。该值已被装箱,因此您可以调用其虚拟成员。


编辑以澄清值类型上的调用接口方法:

var i = 123;
i.ToString();                // not boxed, statically resolves to Int32.ToString()
var o = (object)o;           // box
o.ToString();                // virtual call to object.ToString()
var e = (IEquatable<int>)i;  // box
i.Equals(123);               // virtual call to IEquatable<int>.Equals(int)

编辑以包括乔恩·汉娜(Jon Hanna)的建议。在值类型上调用 System.Object non - virtual方法需要拳击。

var i = 1234;
i.GetType();    // boxes!

您可以在相应的IL中看到它:

ldc.i4.s     123
stloc.0      // i
ldloc.0      // i
box          [mscorlib]System.Int32
call         instance class [mscorlib]System.Type [mscorlib]System.Object::GetType()

Object.GetType()实际上无法调用,并且具有签名:

public extern Type GetType();

但仍然需要拳击。

值类型不包含虚拟函数,所以...

真的?

struct Foo
{
     public override string ToString() =>
         "Sure looks like a virtual call";
     public override bool Equals(object obj) =>
         "So does this one";
}

所有值类型均从object继承,您可以完全覆盖任何虚拟方法。您无法进一步扩展它们的事实是无关紧要的。

对于其他人并同样猛烈地击中了盒子/unbox魔术,我在此处找到了有关该主题的进一步读物:

http://mattwarren.org/2017/08/02/a-look-at-the-nerternals-ob-boxing-in-the-clr/

最新更新