Link to home
Start Free TrialLog in
Avatar of bemara57
bemara57

asked on

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?
ASKER CERTIFIED SOLUTION
Avatar of amx
amx
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of bemara57
bemara57

ASKER

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

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

SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial