Monday, September 21, 2009

Using generic methods to avoid boxing-unboxing

Every time we convert a value type (int,decimal,double,etc) to a reference type (to an object to be specific) a boxing occurs (As MSDN define it , it means to put a value type inside heap) and if we convert an object to an int , an unboxing occurs. Here's an article on MSDN that describes it all.
I'm working on this method that gets a DataRow ,a FieldName and a default value and returns row[fieldname] value (if value is null or DBNull it returns the default value)
My first vesrion of this method is something like this:

public static string GetFieldValue
(DataRow row,
string
fieldname,
string defaultvalue)
{
var value=row[fieldname];
if(value==null || value==DBNull.Value)

return defaultvalue;
return value;
}



Later ,I want to write an overload for this method to work with int values I write something like this:

public static int GetFieldValue
(DataRow row,
string fieldname,
int defaultvalue)
{
var value=row[fieldname];
if(value==null || value==DBNull.Value)

return defaultvalue;
return (int)value;
}



OK an unboxing is happening here and I can't do anything about it.
I think to myself here we have a sign of DRY violation .I can have a single method as a base,something like this:

public static object GetFieldValue
(DataRow row,
string
fieldname,
object fieldvalue)
{
var value=row[fieldname];
if(value==null || value==DBNull.Value)
return defaultvalue;
return value;
}
Then I can rewrite the int version like this:

public static int GetFieldValue
(DataRow row,
string fieldname,
int defaultvalue)
{
return (int)GetFieldValue(row,fieldname,(object) defaultvalue);
}
But wait a second, I can see a boxing here which is not necessary but how can I get rid of it?
One solution that comes to my mind is to change my base method to a generic method:

public static
T GetFieldValue<T>
(DataRow row,
string fieldname,
T defaultValue)
{
var value=row[fieldname];
if(value==null || value==DBNull.Value)
return defaultvalue;
return (T)value;
}



Again if T is a value type an unboxing will occur but there's no boxing and I can rewrite the int version as :

public static int GetFieldValue
(DataRow row,
string fieldname,
int defaultvalue)
{
return GetFieldValue<int>(row,fieldname, defaultvalue);
}

I wrote a test that ran each method for 1,000,000 times and it turns out that the omitted boxing impact is very small.(418 ms for object version vs. 358 ms for generic version)

No comments: