[Webinar] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 370
  • Last Modified:

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?
0
bemara57
Asked:
bemara57
  • 2
  • 2
2 Solutions
 
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
 
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

Featured Post

Vote for the Most Valuable Expert

It’s time to recognize experts that go above and beyond with helpful solutions and engagement on site. Choose from the top experts in the Hall of Fame or on the right rail of your favorite topic page. Look for the blue “Nominate” button on their profile to vote.

  • 2
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now