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?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

amxCommented:
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

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
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
amxCommented:
Thats cool.

The only way i can think of making it less messy is to use the Chain of Responsibilty Design pattern.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C#

From novice to tech pro — start learning today.