ToString() is it really cause boxing ?

More and more times I found myself arguing about ToString() as boxing. As you all know Tostring() is one of the object methods. Well, many programmers tend to believe that when they use ToSting() on value types (int, long, etc’) the CLR should box the value type into object to use the objects ToString(). That’s true if the value type uses the objects method. But, if value type override ToString() (and that’s what really happened) than boxing isn’t necessary since ToString() is part of the value type class.

 

The best way to demonstrate this behavior is by examines IL code. If boxing and unboxing is necessary we will find the box / unbox IL instructions. Take a look at this code which uses assignment of value type to object and backward, there for cause boxing/unboxing and using of Tostring() on value type.

 

int i = 9;

System.Collections.ArrayList oArr = new System.Collections.ArrayList();

//boxing

oArr.Add (i);

//unboxing

int iRet = (int)oArr[0];

 

//no boxing at all

string str = i.ToString();

 

The generated IL code that uses boxing/unboxing for using ArrayList with value types, as accepted. For using ToString() with value type you can see that IL uses int32 ToString() thus not using boxing.

 

.locals init ([0] int32 i,

           [1] class [mscorlib]System.Collections.ArrayList oArr,

           [2] int32 iRet,

           [3] string str)

. . .

//000015:                                 int i = 9;

  IL_0006:  ldc.i4.s   9

  IL_0008:  stloc.0

//000016:                                 System.Collections.ArrayList oArr = new System.Collections.ArrayList();

  IL_0009:  newobj     instance void [mscorlib]System.Collections.ArrayList::.ctor()

  IL_000e:  stloc.1

//000017:                                 //boxing

//000018:                                 oArr.Add (i);

  IL_000f:  ldloc.1

  IL_0010:  ldloc.0

  IL_0011:  box        [mscorlib]System.Int32

  IL_0016:  callvirt   instance int32 [mscorlib]System.Collections.ArrayList::Add(object)

  IL_001b:  pop

//000019:                                 //unboxing

//000020:                                 int iRet = (int)oArr[0];

  IL_001c:  ldloc.1

  IL_001d:  ldc.i4.0

  IL_001e:  callvirt   instance object [mscorlib]System.Collections.ArrayList::get_Item(int32)

  IL_0023:  unbox      [mscorlib]System.Int32

  IL_0028:  ldind.i4

  IL_0029:  stloc.2

//000021:

//000022:                                 //no boxing att all

//000023:                                 string str = i.ToString();

  IL_002a:  ldloca.s   i

  IL_002c:  call       instance string [mscorlib]System.Int32::ToString()

  IL_0031:  stloc.3

//000024:                     }

3 Comments

  • Along these same lines, I've wondered which is better, to cast an object (known to be a string) to string or to call .ToString()?



  • I'd go with casting, as it more clearly represents your intent. You are dealing with a known string, or so you think. If you cast it and it's not a string, you'll throw an exception, which is what should happen. If it's not a string, and you call .ToString()(), you'll still get a string. Of course if you want a string and you don't care whether the underlying variable is a string or not then you would call .ToString();



    Best, I think, is something like:



    string sResult = ViewState[assumedString] as string;



    if it's not a string, sResult will be null;



    But suppose you don't know if it's an int or a string, but you want to end up with a string



    Object obj = ViewState[whatever];

    if (obj != null)

    string sResult = obj.ToString();











  • "But suppose you don't know if it's an int or a string, but you want to end up with a string

    Object obj = ViewState[whatever];
    if (obj != null)
    string sResult = obj.ToString(); "

    In your example, you are getting the value from ViewState, which will always return a String, no matter what the data in it is, unless you cast the return value.

Comments have been disabled for this content.