object.ToString()如何处理盒装值类型?

时间:2017-09-08 16:59:35

标签: c# object tostring value-type

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如何知道它在内部持有什么类型以便进行正确的字符串格式化。

3 个答案:

答案 0 :(得分:4)

调用函数在调用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 - 虚方法需要装箱。

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();

但它还需要拳击。

答案 1 :(得分:0)

  

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

真的?

struct Foo
{
     public override string ToString() =>
         "Sure looks like a virtual call";

     public override bool Equals(object obj) =>
         "So does this one";
}

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

答案 2 :(得分:0)

对于那些来到这里并同样猛烈抨击盒子/盒子魔法的人,我在这里找到了一些关于这个主题的可靠的进一步阅读:

http://mattwarren.org/2017/08/02/A-look-at-the-internals-of-boxing-in-the-CLR/