How to convert arbitrary objects to class property?

I have a process that loads up a class from a DataTable. The DataTable gets loaded up from some random database beforehand. The problem is if the DataTable's cell value that is being mapped to the class property is sometimes not the same type, so it throws a run-time exception. For example, if I'm filling in a class property of type int with a DataTable's cell value that is a string (like "2"), then it fails. So I want to put in a validation and conversion in place to handle this. Can anyone help suggest a way to do this?
bemara57Asked:
Who is Participating?
 
amxConnect With a Mentor Commented:
use the is statement to determine the correct type and then try a conversion method like tryParse for example which will return a default value if the ocnversion fails
int i = 0;
object o = (object)i;
 
        if (i is int)
        {
            int myVar = 0;
            int.TryParse("2", out myVar);
        }

Open in new window

0
 
bemara57Author Commented:
The issue is that I use Reflections to load up the class. See my attached code that I use to load a DataTable to an arbitrary class. I pass in a DataTable and a hashtable that maps the DataTable column to the right class property (which is where I use Reflection because I only know the property name, not the reference). It then returns a strongly typed List of objects.

So what can I do in my 'try' clause? This is where I'm having trouble converting the DataTable cell to the property. Here are some exceptions I'm getting w/ stack traces:

System.ArgumentException: Object of type 'System.Double' cannot be converted to type 'System.String'. at System.RuntimeType.CheckValue(Object value, Binder binder, CultureInfo culture, BindingFlags invokeAttr) at System.Reflection.MethodBase.CheckArguments(Object[] parameters, Binder binder, BindingFlags invokeAttr, CultureInfo culture, Signature sig) at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks) at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) at System.Reflection.RuntimePropertyInfo.SetValue(Object obj, Object value, BindingFlags invokeAttr, Binder binder, Object[] index, CultureInfo culture) at ...

System.ArgumentException: Object of type 'System.Double' cannot be converted to type 'System.Int32'. at System.RuntimeType.CheckValue(Object value, Binder binder, CultureInfo culture, BindingFlags invokeAttr) at System.Reflection.MethodBase.CheckArguments(Object[] parameters, Binder binder, BindingFlags invokeAttr, CultureInfo culture, Signature sig) at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks) at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) at System.Reflection.RuntimePropertyInfo.SetValue(Object obj, Object value, BindingFlags invokeAttr, Binder binder, Object[] index, CultureInfo culture) at
        public static List<T> ToClassCollection<T>(this DataTable param, Hashtable mappings) where T : new()
        {
            List<T> col = new List<T>();
 
            foreach (DataRow row in param.Rows)
            {
                T obj = new T();
 
                foreach (DictionaryEntry map in mappings)
                {
                    if (row[map.Value.ToString()] != DBNull.Value)
                    {
                        try
                        {
                            obj.GetType().GetProperty(map.Key.ToString()).SetValue(
                                obj, row[map.Value.ToString()], BindingFlags.Default, null, null, null);
 
                            col.Add(obj);
                        }
                        catch (Exception ex)
                        {
                            Helpers.LogException(ex);
                        }
                    }
                }
            }
 
            return col;
        }

Open in new window

0
 
bemara57Author Commented:
I think I found a way to do it, but it's still a little messy:
                foreach (DictionaryEntry map in mappings)
                {
                    if (row[map.Value.ToString()] != DBNull.Value)
                    { 
                        PropertyInfo propertyInfo = objInstance.GetType().GetProperty(map.Key.ToString());
                        object tableCell = row[map.Value.ToString()];
 
                        try
                        {
                            if (propertyInfo.PropertyType == typeof(string))
                                propertyInfo.SetValue(objInstance, tableCell.ToString(), null);
                            else if (propertyInfo.PropertyType == typeof(bool))
                                propertyInfo.SetValue(objInstance, Convert.ToBoolean(tableCell), null);
                            else if (propertyInfo.PropertyType == typeof(int))
                                propertyInfo.SetValue(objInstance, Convert.ToInt32(tableCell), null);
                            else if (propertyInfo.PropertyType == typeof(decimal))
                                propertyInfo.SetValue(objInstance, Convert.ToDecimal(tableCell), null);
                            else if (propertyInfo.PropertyType == typeof(double))
                                propertyInfo.SetValue(objInstance, Convert.ToDouble(tableCell), null);
                            else if (propertyInfo.PropertyType == typeof(DateTime))
                                propertyInfo.SetValue(objInstance, Convert.ToDateTime(tableCell), null);
 
                            col.Add(objInstance);
                        }
                        catch (Exception ex)
                        {
                            Helpers.LogException(ex);
                        }
                    }
                }

Open in new window

0
 
amxConnect With a Mentor Commented:
Thats cool.

The only way i can think of making it less messy is to use the Chain of Responsibilty Design pattern.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.