Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert.ChangeType() fails on Nullable Types

I want to convert a string to an object property value, whose name I have as a string. I am trying to do this like so:

string modelProperty = "Some Property Name"; string value = "SomeValue"; var property = entity.GetType().GetProperty(modelProperty); if (property != null) {     property.SetValue(entity,          Convert.ChangeType(value, property.PropertyType), null); } 

The problem is this is failing and throwing an Invalid Cast Exception when the property type is a nullable type. This is not the case of the values being unable to be Converted - they will work if I do this manually (e.g. DateTime? d = Convert.ToDateTime(value);) I've seen some similiar questions but still can't get it to work.

like image 403
iboeno Avatar asked Aug 20 '10 13:08

iboeno


2 Answers

Untested, but maybe something like this will work:

string modelProperty = "Some Property Name"; string value = "Some Value";  var property = entity.GetType().GetProperty(modelProperty); if (property != null) {     Type t = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType;      object safeValue = (value == null) ? null : Convert.ChangeType(value, t);      property.SetValue(entity, safeValue, null); } 
like image 137
LukeH Avatar answered Oct 07 '22 02:10

LukeH


You have to get the underlying type in order to do that...

Try this, I've used it successfully with generics:

//Coalesce to get actual property type... Type t = property.PropertyType(); t = Nullable.GetUnderlyingType(t) ?? t;  //Coalesce to set the safe value using default(t) or the safe type. safeValue = value == null ? default(t) : Convert.ChangeType(value, t); 

I use it in a number of places in my code, one example is a helper method I use for converting database values in a typesafe manner:

public static T GetValue<T>(this IDataReader dr, string fieldName) {     object value = dr[fieldName];      Type t = typeof(T);     t = Nullable.GetUnderlyingType(t) ?? t;      return (value == null || DBNull.Value.Equals(value)) ?          default(T) : (T)Convert.ChangeType(value, t); } 

Called using:

string field1 = dr.GetValue<string>("field1"); int? field2 = dr.GetValue<int?>("field2"); DateTime field3 = dr.GetValue<DateTime>("field3"); 

I wrote a series of blog posts including this at http://www.endswithsaurus.com/2010_07_01_archive.html (Scroll down to the Addendum, @JohnMacintyre actually spotted the bug in my original code which led me down the same path you're on now). I have a couple of small modifications since that post that includes conversion of enum types also so if your property is an Enum you can still use the same method call. Just add a line in to check for enum types and you're off to the races using something like:

if (t.IsEnum)     return (T)Enum.Parse(t, value); 

Normally you'd have some error checking or use TryParse instead of Parse, but you get the picture.

like image 40
BenAlabaster Avatar answered Oct 07 '22 02:10

BenAlabaster