Showing posts with label Generics. Show all posts
Showing posts with label Generics. Show all posts

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)