2014-02-09 4 views
5

Was ist der Unterschied zwischen ToString Calling von zwei Variablen?Unterschied zwischen ValueType.ToString und ReferenceType.ToString

int i = 0; 
i.ToString(); 

Hat Aufruf i.ToString() werde ich boxed machen zuerst, dann rufen Sie ToString oder i bereits boxed vor ToString() aufrufen?

+0

nicht zuerst und nicht die zweite. Da das 'int' von' object' abgeleitet ist, hat es 'ToString()' überladen. –

+0

Hier ist kein Boxing involviert –

Antwort

4

int ist ein Alias ​​für System.Int32 struct-Typ (implizit versiegelt), der ein Verfahren aufweist Int32.ToString() und dies ist ein Verfahren, das in der zweiten Zeile des Codes aufgerufen, so dass keine Typumwandlung auftritt.

System.Int32 ist von System.ValueType abgeleitet, die von System.Object abgeleitet ist. Int32.ToString() überschreibt ValueType.ToString(), wodurch Object.ToString() überschrieben wird.

Der beste Weg, ob Boxen überprüfen auftritt, ist IL-Code, um zu sehen (ich habe mit ILSpy worden):

using System; 

namespace BoxingTest 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      int i = 0; 
      string s1 = i.ToString(); 
     } 
    } 
} 

zu übersetzt:

.method private hidebysig static 
    void Main (
     string[] args 
    ) cil managed 
{ 
    // Method begins at RVA 0x2050 
    // Code size 12 (0xc) 
    .maxstack 1 
    .entrypoint 
    .locals init (
     [0] int32 i, 
     [1] string s1 
    ) 

    IL_0000: nop 
    IL_0001: ldc.i4.0 
    IL_0002: stloc.0 
    IL_0003: ldloca.s i 
    IL_0005: call instance string [mscorlib]System.Int32::ToString() 
    IL_000a: stloc.1 
    IL_000b: ret 
} // end of method Program::Main 

Sie, dass keine Boxen sehen aufgetreten und dass System.Int32::ToString() wurde aufgerufen.

Boxing hätte stattgefunden, wenn z.B. Sie haben Ihre int zu object explizit oder implizit gegossen. (Beachten Sie, dass die Umstellung auf object Typ nicht der einzige Fall ist, wenn Boxen geschieht)

Explicit Casting object eingeben:

using System; 

namespace BoxingTest 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      int i = 0; 
      string s2 = ((object)i).ToString(); 
     } 
    } 
} 

gibt:

.method private hidebysig static 
    void Main (
     string[] args 
    ) cil managed 
{ 
    // Method begins at RVA 0x2050 
    // Code size 16 (0x10) 
    .maxstack 1 
    .entrypoint 
    .locals init (
     [0] int32 i, 
     [1] string s2 
    ) 

    IL_0000: nop 
    IL_0001: ldc.i4.0 
    IL_0002: stloc.0 
    IL_0003: ldloc.0 
    IL_0004: box [mscorlib]System.Int32 
    IL_0009: callvirt instance string [mscorlib]System.Object::ToString() 
    IL_000e: stloc.1 
    IL_000f: ret 
} // end of method Program::Main 

Boxen durch implizite Umwandlung:

using System; 

namespace BoxingTest 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      int i = 0; 
      object o = i; 
      string s3 = o.ToString(); 
     } 
    } 
} 

ergibt:

.method private hidebysig static 
    void Main (
     string[] args 
    ) cil managed 
{ 
    // Method begins at RVA 0x2050 
    // Code size 18 (0x12) 
    .maxstack 1 
    .entrypoint 
    .locals init (
     [0] int32 i, 
     [1] object o, 
     [2] string s3 
    ) 

    IL_0000: nop 
    IL_0001: ldc.i4.0 
    IL_0002: stloc.0 
    IL_0003: ldloc.0 
    IL_0004: box [mscorlib]System.Int32 
    IL_0009: stloc.1 
    IL_000a: ldloc.1 
    IL_000b: callvirt instance string [mscorlib]System.Object::ToString() 
    IL_0010: stloc.2 
    IL_0011: ret 
} // end of method Program::Main 

In allen drei Fällen Saiten Wert haben "0" weil Object.ToString() die ursprüngliche Art der boxed Variable kennt und nennt ToString() `dieses Typs.

Dies ist der IL-Code des Object.ToString():

.method public hidebysig newslot virtual 
    instance string ToString() cil managed 
{ 
    .custom instance void __DynamicallyInvokableAttribute::.ctor() = (
     01 00 00 00 
    ) 
    // Method begins at RVA 0x2052 
    // Code size 12 (0xc) 
    .maxstack 8 

    IL_0000: ldarg.0 
    IL_0001: call instance class System.Type System.Object::GetType() 
    IL_0006: callvirt instance string System.Object::ToString() 
    IL_000b: ret 
} // end of method Object::ToString 
0

Technisch int erbt von System.ValueType welcher intern von Objekt erbt. Aber um Ihre Frage zu beantworten, gibt es keine Leistungseinbußen. Alle Werttypen sind versiegelte Typen, von denen sie weder abgeleitet noch abgeleitet werden können. Also, obwohl Hamlet Hakobyan darauf hinweist, dass ToString von int überschrieben wird, ist es effektiv versiegelt und es wird kein virtueller Versand durchgeführt, der ein Boxing erfordern würde.