Jun 10, 2011

Convert string to a known type (using its default converter)

I was in a need to get a type, instantiate it and then fill its properties (I'm currently doing an engine that will give me an instant CRUD UI).

So what I basically needed was to be able to fill a new object instance out of a Hashtable (the key is the name of the property and the value is its string representation).

I wanted to be able to convert that string value into the type it needs to be.
Here is some code to help you get it:

foreach(string strPropertyName in htValues.Keys)
{
PropertyInfo pi = entity.GetType()
.GetProperties()
.ToList()
.FirstOrDefault(property => property.Name == strPropertyName);
}
(this is kind of pretotype so don't blame me if you don't like the code :).

In the above code I am iterating in the keys of the hashtable, so if I have an user object it will strPropertyName will hold "FirstName", then "LastName".
So far so good, I am able to fill the object and send it to the EntityFramework for DB Persistance.

The problem was when the strPropertyName was holding "BirthDate" as it is a DateTime and the EntityFramework or the Reflection (not quite sure which one) was crying it can't Convert the string to the respective type for me.

Here is how I solved the problem:
// Create a new Instance of the given type.
object entity = Activator.CreateInstance(this.EntityType);
// Iterate through all the properties.
foreach(string strPropertyName in htValues.Keys)
{
// Get the property with that name:
PropertyInfo pi = entity.GetType()
.GetProperties()
.ToList()
.FirstOrDefault(property => property.Name == strPropertyName);
// Get the default type converter for the given property type:
TypeConverter converter = TypeDescriptor.GetConverter(pi.PropertyType);
// Set the value by converting non-values to the given type
// and setting null where it is a null value.
pi.SetValue(entity, htValues[pi.Name] == null ? null : converter.ConvertFromString(htValues[pi.Name].ToString()), new object[] { });
}

Basically the thing you (and I!) need to remember is that the TypeDescriptor class has a GetConverter() method that takes a type and returns a TypeConvertor for that type.

Now in order to be able to convert from string to that type you just need to call .ConvertFromString(string value) of the TypeConverter returned by the TypeDescriptor.

Hope this helps someone out there. To me it seems it can give you a great deal of abstraction and I (for some reason) believe this is heavilly used in nowadays OR/M's.

Jun 9, 2011

Get the underlying type out of a Nullable

It appeared to be really simple actually, this post title suggest the solution:

Type nonNullableType = null;
if (property.PropertyType.IsGenericType && property.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
nonNullableType = new NullableConverter(property.PropertyType).UnderlyingType;
else
nonNullableType = property.PropertyType;

What we actually do is to check if the type is nullable or not, if so - we are getting its Underlying type, and if not - we are getting the type itself.

Check if a type is Nullable or not

I was in a need to determine if the type of PropertyInfo is a nullable or not.
Here is what I've found on MSDN about this:

property.PropertyType.IsGenericType && property.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>)

So you basically need to determine if the type is generic (makes sense as nullable is a type that takes T (Nullable)) and then to check if the type is a Nullable then.

Now, I really wondered do I really need both checks?
As it was coded that way at MSDN I first didn't look at that, but I wanted to tackle it a bit more.

First I thought that the first one is needed to protect you from the null value returned by the GetGenericTypeDefinition() method.
But what's the problem even if it does?
Well, you get InvalidOperationException saying "This operation is only valid on generic types.".

So you definetelly need both checks ;).
It is kind of ugly for me, maybe it will be better to create an extender to the Type type. Something like "IsGeneric()", but the Is prefix always suggests property while this is a method.

Anyway, I'll go with that.
In the next post I'll show you how to get the type out of a Nullable<>.