Click here to Skip to main content
15,891,513 members
Articles / Programming Languages / C#

Boxing and the Unified Type System

Rate me:
Please Sign up or sign in to vote.
0.00/5 (No votes)
17 Jul 2015CPOL 6.5K   1   1
Boxing and the Unified Type System

In C#, all types inherit from a single root, the object type. This allows for primitive types such as int, boolean, and char to be addressed as objects throughout the system. There is some debate as to whether or not this is a good thing as there is some overhead involved in packaging up or “boxing” primitive types. Other languages, such as Java, don’t require boxing primitive types into reference types, thus trading overhead for convenience. However, in the .NET Framework, boxing primitive types is standard practice.

I was curious as to how much overhead is involved in boxing and unboxing primitive, value types in and out of the Object reference type, so I wrote this small test program.

C#
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;

namespace BoxingAndGenerics
{
 class Program
 {
 // This test shows that there is significant overhead when boxing and unboxing value
 // types (int, string, double) into the Object type.
 // All explicit variable declarations have been left in the code instead of using var for clarity
 static void Main()
 {
   const int numberOfInterations = 8000000;

   // create an ArrayList of strings
   var startTime = Stopwatch.GetTimestamp();
   ArrayList aListOfStrings = new ArrayList();
   for (var i = 0; i< numberOfInterations; i++)
   {
     string theString = i.ToString();
     aListOfStrings.Add(theString);

    string unpackedString = (string)aListOfStrings[i];
   }
   var ellapsedTime = (Stopwatch.GetTimestamp() - startTime) / (double) Stopwatch.Frequency;
   Console.WriteLine("Time to create string array with boxing: {0}", ellapsedTime);

   // create a List<String> of strings
   startTime = Stopwatch.GetTimestamp();
   List<string> aGenericListOfStrings = new List<string>();
   for (var i = 0; i < numberOfInterations; i++)
   {
     string theString = i.ToString();
     aGenericListOfStrings.Add(theString);

     string unpackedString = (string)aGenericListOfStrings[i];
   }
   ellapsedTime = (Stopwatch.GetTimestamp() - startTime) / (double)Stopwatch.Frequency;
   Console.WriteLine("Time to create string array using Generic array: {0}", ellapsedTime);


   // create an ArrayList of ints
   startTime = Stopwatch.GetTimestamp();
   ArrayList aListOfInts = new ArrayList();
   for (var i = 0; i < numberOfInterations; i++)
   {
      aListOfInts.Add(i);

      int unpackedInt = (int)aListOfInts[i];
   }
   ellapsedTime = (Stopwatch.GetTimestamp() - startTime) / (double)Stopwatch.Frequency;
   Console.WriteLine("Time to create int array with boxing: {0}", ellapsedTime);

   // create a List<int> of ints
   startTime = Stopwatch.GetTimestamp();
   List<int> aGenericListOfInts = new List<int>();
   for (var i = 0; i < numberOfInterations; i++)
   {
     aGenericListOfInts.Add(i);

     int unpackedInt = (int)aGenericListOfInts[i];
   }
   ellapsedTime = (Stopwatch.GetTimestamp() - startTime) / (double)Stopwatch.Frequency;
   Console.WriteLine("Time to create int array using Generic array: {0}", ellapsedTime);


   // create an ArrayList of doubles
   startTime = Stopwatch.GetTimestamp();
   ArrayList aListOfDoubles = new ArrayList();
   for (var i = 0; i < numberOfInterations; i++)
   {
     double theDouble = (double) i;
     aListOfDoubles.Add(theDouble);

     double unpackedDouble = (double)aListOfDoubles[i];
   }
   ellapsedTime = (Stopwatch.GetTimestamp() - startTime) / (double)Stopwatch.Frequency;
   Console.WriteLine("Time to create double array with boxing: {0}", ellapsedTime);

   // create a List<int> of doubles
   startTime = Stopwatch.GetTimestamp();
   List<double> aGenericListOfDoubles = new List<double>();
   for (var i = 0; i < numberOfInterations; i++)
   {
     double theDouble = (double) i;
     aGenericListOfDoubles.Add(theDouble);

     double unpackedDouble = (double)aGenericListOfDoubles[i];
   }
   ellapsedTime = (Stopwatch.GetTimestamp() - startTime) / (double)Stopwatch.Frequency;
   Console.WriteLine("Time to create double array using Generic array: {0}", ellapsedTime);

   // Put in a read so that we can take a look at the output
   Console.ReadLine();
  }
 }
}

After running the program, this is the output:

Boxing and Generics Output

As expected, strings are always going to be expensive to deal with due to their immutable nature. Interestingly, you can see that numeric types are about 10 times slower when dealing with boxing. Therefore, when possible we should use generic collection types so that the CLR knows in advance the type that it is dealing with and can avoid the overhead of boxing.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Technical Lead
United States United States
I'm a learner/coder/leader who is curious about how technologies and people work together to solve interesting problems. I have a passion for software and doing what I can to improve the lives of the people who create and use it.

Comments and Discussions

 
GeneralStrings aren't expensive Pin
John Brett19-Jul-15 21:11
John Brett19-Jul-15 21:11 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.