Last night I answerd a interesting question on the Asp.Net Forums that I thought is worth a post. The objective was to create a method using Generics that could get a value from the Session only instead of returning a Object it would return the value in the type defined in the generic method. Just to make the demonstration easier I'll use a Dictionary instead of the Session but it works just the same:
class TypeTest
{
private static Dictionary<string, object> PretendSession = new Dictionary<string, object>();
public static void Test()
{
PretendSession.Add("int", 10M);
Console.Out.WriteLine(Get<int>("int"));
}
public static T Get<T>(string theKey)
{
object aSessionObject = PretendSession[theKey];
if (aSessionObject == null)
{
return default(T);
}
return (T) aSessionObject;
}
}
This code works well for most cases but you can get in trouble when you work with Value Types. Look at code that follows and to undestand the problems with boxing and unboxing value types:
//doesn't work, need explicit cast
int i = 10M;
//now it's fine
int i = (int)10M;
//boxing and unboxing work fine
object o = 10;
int i = (int)o;
//doesn't work
object o = 10M;
int i = (int)o;
When you know exactaly what is the type of you are putting inside the Session it all goes fine. When you don't know what type you are working with you need the help of the Convert class to convert the type before casting it. To do this we test if the object is of type ValueType and if it is, before casting it we use the ChangeType method of the Convert class to make sure that the object really contains the type we will try to cast it to.
class TypeTest
{
static Dictionary<string, object> PretendSession = new Dictionary<string, object>();
public static void Test()
{
PretendSession.Add("int", 10M);
Console.Out.WriteLine(Get<int>("int"));
}
public static T Get<T>(string theKey)
{
object aSessionObject = PretendSession[theKey];
if (aSessionObject == null)
{
return default(T);
}
if (aSessionObject is ValueType)
{
return (T)Convert.ChangeType(aSessionObject, typeof(T));
}
return (T)aSessionObject;
}
}
Now you should be safe to use your Get<T> method. Hope this can help other people that face this same issue.