4

I'm trying to build a generic mapper which will convert the results of a SqlDataReader into a class object.

Here is the basic structure for my code:

public interface IObjectCore
    {
        //contains properties for each of my objects
    }

    public class ObjectMapper<T> where T : IObjectCore, new()
    {
        public List<T> MapReaderToObjectList(SqlDataReader reader)
        {
            var resultList = new List<T>();
            while (reader.Read())
            {
                var item = new T();
                Type t = item.GetType();
                foreach (PropertyInfo property in t.GetProperties())
                {
                    Type type = property.PropertyType;
                    string readerValue = string.Empty;

                    if (reader[property.Name] != DBNull.Value)
                    {
                        readerValue = reader[property.Name].ToString();
                    }

                    if (!string.IsNullOrEmpty(readerValue))
                    {
                        property.SetValue(property, readerValue.To(type), null);
                    }

                }
            }
            return resultList;
        }
    }

    public static class TypeCaster
    {
        public static object To(this string value, Type t)
        {
            return Convert.ChangeType(value, t);
        }
    }

For the most part it seems to work, but as soon as it tries to set the value of the property, I get the following error:

Object does not match target type

on the line where I have property.SetValue.

I have tried everything and I don't see what I might be doing wrong.

Mast
  • 1,788
  • 4
  • 29
  • 46
Wondercricket
  • 7,651
  • 2
  • 39
  • 58
  • Db actions has a cost. Add reflection to it, it's going to be noticeably slower. Worse, you do it inside the loop. You **should** move the reflection part outside the loop, and preferably rely on expression trees instead of reflection. See [this answer](http://stackoverflow.com/questions/19841120/listt-property-binding-to-dbdatareader-issue/19845980#19845980) for e.g. – nawfal Jul 28 '15 at 09:12
  • Related: http://stackoverflow.com/questions/812034/fastest-way-to-use-reflection-for-converting-datareader-to-list, http://stackoverflow.com/questions/19841120/generic-dbdatareader-to-listt-mapping, http://codereview.stackexchange.com/questions/58251/transform-datareader-to-listt-using-reflections – nawfal Aug 01 '15 at 11:54
  • @nawfal Have you looked at the date this was posted? – Mast Aug 01 '15 at 12:00
  • @Mast yes. Are my comments no longer relevant? – nawfal Aug 01 '15 at 12:01

2 Answers2

4

You are trying to set the value of the property you are looping through, I think your intent is to set the value of the newly created item that you have because that is going to match the Type that you are passing it based on item.GetType()

var item = new T();
//other code
property.SetValue(item , readerValue.To(type), null);

instead of

property.SetValue(property, readerValue.To(type), null);

Also per comment, make sure you have:

resultList.Add(item);
CodeLikeBeaker
  • 20,682
  • 14
  • 79
  • 108
1

Looks like this part is wrong:

property.SetValue(property, readerValue.To(type), null);

Are you certain you want to apply SetValue by passing property to it? Looks to me you should pass the object of type T which is item.

This then becomes:

property.SetValue(item, readerValue.To(type), null);

JonH
  • 32,732
  • 12
  • 87
  • 145