代码之家  ›  专栏  ›  技术社区  ›  cazicss

对象如何。ToString()处理装箱值类型?

  •  1
  • cazicss  · 技术社区  · 7 年前
    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() 调用并正确显示特定于值类型的字符串格式。

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

    Object 知道它在内部保存的类型,以便进行正确的字符串格式设置。

    3 回复  |  直到 7 年前
        1
  •  4
  •   Drew Noakes    7 年前

    调用函数在调用之前将参数装箱 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();
    

    然而,它仍然需要拳击。

        2
  •  0
  •   InBetween    7 年前

    真正地

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

    所有值类型都继承自 object

        3
  •  0
  •   cazicss    7 年前

    对于其他人来说,他们同样会对盒子/非盒子魔法大发雷霆,我在这里找到了一些关于这个主题的深入阅读:

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