CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

David Hayden [MVP C#]

         .NET Tutorials, Patterns, and Practices

Boxing - The Conversion of Value Types to Reference Types - A Quick Visit

Raymond will be doing a more thorough examination of boxing and unboxing in the near future, so I am just going to do a quick visit (very quick) per Brendan's comments in my post: Overriding System.Object.ToString() and Implementing IFormattable.  Check the comments for details.

For a more thorough description of Boxing in a book, I recommend buying Jeffrey Richter's Applied Microsoft .NET Framework Programming.  It is one of the few books that has snuck out of my office and into my lanai for casual reading in the backyard.

Boxing Defined

Boxing is the mechanism by which a value type is converted into a reference type.

Boxing occurs when a method, for example, is expecting a reference type and gets a value type. When this happens, the C# compiler automatically detects that boxing needs to occur and emits the necessary IL code for it to happen.  In general, boxing has a negative impact on performance and can actually cause bugs if you aren't fully aware of its consequences.  I will let Raymond elaborate more on that in his post.

One of the overloaded Console.WriteLine methods looks like this:

Console.WriteLine Method

void Console.WriteLine(string format, Object arg0, Object arg1);

As you can see, Console.WriteLine is expecting reference types (i.e. Object), not value types.  If you use this overloaded method and pass it a value type as one of the arguments, boxing will occur.  There are no warnings or compiler errors.  The compiler will emit the necessary IL code to box the value type (i.e. convert it to a reference type for you) and you are none the wiser (unless you look at the IL).

Here is example code for which boxing occurs.  Notice that I am passing the integer x (value type) directly to Console.WriteLine (look way down in Main()).  This will cause boxing which you can see in the IL code.

Boxing
using System;

public class Person
{
    #region Private Members

    private string _firstname;
    private string _lastname;
    private int _age;

    #endregion

    #region Properties

    public string Firstname
    {
        get { return _firstname; }
        set { _firstname = value; }
    }

    public string Lastname
    {
        get { return _lastname; }
        set { _lastname = value; }
    }

    public int Age
    {
        get { return _age; }
        set { _age = value; }
    }

    #endregion

    #region Contructors

    public Person (string firstname, string lastname, int age)
    {
        if (firstname == null || firstname.Length == 0)
            throw new ArgumentNullException("firstname");

        if (lastname == null || lastname.Length == 0)
            throw new ArgumentNullException("lastname");

        _firstname = firstname;
        _lastname = lastname;
        _age = age;
    }

    #endregion
}

public class TestClass
{
    public static void Main()
    {
        int x = 5;
        Person p = new Person("David","Hayden",99);
        Console.WriteLine("{0} {1}", p, x);
        Console.ReadLine();
    }
}

 

IL Code With Boxing

.method public hidebysig static void  Main() cil managed
{
  .entrypoint
  // Code size       44 (0x2c)
  .maxstack  4
  .locals init ([0] int32 x,
           [1] class Person p)
  IL_0000:  ldc.i4.5
  IL_0001:  stloc.0
  IL_0002:  ldstr      "David"
  IL_0007:  ldstr      "Hayden"
  IL_000c:  ldc.i4.s   99
  IL_000e:  newobj     instance void Person::.ctor(string,
                                                   string,
                                                   int32)
  IL_0013:  stloc.1
  IL_0014:  ldstr      "{0} {1}"
  IL_0019:  ldloc.1
  IL_001a:  ldloc.0
  IL_001b:  box        [mscorlib]System.Int32
  IL_0020:  call       void [mscorlib]System.Console::WriteLine(string,
                                                                object,
                                                                object)
  IL_0025:  call       string [mscorlib]System.Console::ReadLine()
  IL_002a:  pop
  IL_002b:  ret
} // end of method TestClass::Main

In the following example, boxing does not occur.  I pass x.ToString() into the Console.WriteLine method (again way down in Main()), which is a reference type and thus does not need to go through the boxing process.

No Boxing
using System;

public class Person
{
    #region Private Members

    private string _firstname;
    private string _lastname;
    private int _age;

    #endregion

    #region Properties

    public string Firstname
    {
        get { return _firstname; }
        set { _firstname = value; }
    }

    public string Lastname
    {
        get { return _lastname; }
        set { _lastname = value; }
    }

    public int Age
    {
        get { return _age; }
        set { _age = value; }
    }

    #endregion

    #region Contructors

    public Person (string firstname, string lastname, int age)
    {
        if (firstname == null || firstname.Length == 0)
            throw new ArgumentNullException("firstname");

        if (lastname == null || lastname.Length == 0)
            throw new ArgumentNullException("lastname");

        _firstname = firstname;
        _lastname = lastname;
        _age = age;
    }

    #endregion
}

public class TestClass
{
    public static void Main()
    {
        int x = 5;
        Person p = new Person("David","Hayden",99);
        Console.WriteLine("{0} {1}", p, x.ToString());
        Console.ReadLine();
    }
}

 

IL Code Without Boxing

.method public hidebysig static void  Main() cil managed
{
  .entrypoint
  // Code size       45 (0x2d)
  .maxstack  4
  .locals init ([0] int32 x,
           [1] class Person p)
  IL_0000:  ldc.i4.5
  IL_0001:  stloc.0
  IL_0002:  ldstr      "David"
  IL_0007:  ldstr      "Hayden"
  IL_000c:  ldc.i4.s   99
  IL_000e:  newobj     instance void Person::.ctor(string,
                                                   string,
                                                   int32)
  IL_0013:  stloc.1
  IL_0014:  ldstr      "{0} {1}"
  IL_0019:  ldloc.1
  IL_001a:  ldloca.s   x
  IL_001c:  call       instance string [mscorlib]System.Int32::ToString()
  IL_0021:  call       void [mscorlib]System.Console::WriteLine(string,
                                                                object,
                                                                object)
  IL_0026:  call       string [mscorlib]System.Console::ReadLine()
  IL_002b:  pop
  IL_002c:  ret
} // end of method TestClass::Main

That is the 10 cent tour of boxing!



Comments

The Mit's Blog said:

# April 10, 2005 5:16 AM
Check out Devlicio.us!

Our Sponsors

This Blog

Syndication

News

CodeBetter.Com Home