Improvements with reflection and generics

2019-07-27 11:26发布

Following on from another question on Stack Overflow by a different user, I thought I would try the code and see if I could improve it.

I would like clarification on a number of things:

  1. I am assuming that getting property information via reflection is costly? Correct?
  2. With PropertyInfo.SetValue(Object, Object, Object[]) what is the last parameter for? Am I safe passing in null?
  3. Is there any other improvements that are obvious in my code?

The whole point is a learning exercise to see if I can create something like Dapper (which is very nice) but without the nasty looking (because i have no idea) IL emit stuff. With this is mind, I tried to implement some sort of caching with the assumtion that reflection is bad for perfomance.


The Code

    private T CreateItemFromRow<T>(SqlDataReader row, List<PropertyInfo> properties, Dictionary<String, Int32> schema) where T : new()
    {
        T item = new T();
        if (schema != null && properties != null && row != null)
        {
            foreach (var property in properties)
            {
                if (schema.ContainsKey(property.Name))
                {
                    // is this ok?
                    if (row[0].GetType() == property.PropertyType)
                    {
                        property.SetValue(item, row[schema[property.Name]], null);
                    }
                    else
                    {
                        property.SetValue(item, Convert.ChangeType(row[schema[property.Name]], property.PropertyType), null);
                    }
                }
            }
        }
        return item;
    }

The properties is passed in from this method:

    private List<PropertyInfo> GetPropertyInformation<T>()
    {
        List<PropertyInfo> properties;

        Type _T = typeof(T);
        if (!PropertyCache.ContainsKey(_T))
        {
            properties = _T.GetProperties().ToList();
            PropertyCache.Add(_T, properties);
        }
        else
        {
            properties = PropertyCache[_T];
        }
        return properties;
    }

And this is the declaration of PropertyCache

private static Dictionary<Type, List<PropertyInfo>> PropertyCache { get; set; }

3条回答
Animai°情兽
2楼-- · 2019-07-27 11:37
  1. Getting property information via reflection is costly, but so is accessing the properties via reflection. You're not gaining nearly as much from this approach as you could gain by avoiding reflection altogether. Besides, unless you have determined that this code is a performance bottleneck, most optimization here will be premature anyway.
  2. With PropertyInfo.SetValue(Object, Object, Object[]), the last parameter has to do with Index properties (e.g. dict[0] actually accesses an index property, and would pass an array with the 0 in that third parameter).
  3. I'd suggest using a ConcurrentDictionary for your PropertyCache. It will help to both simplify your code and make it thread-safe.
查看更多
一夜七次
3楼-- · 2019-07-27 11:39

It sounds a bit like you're considering writing AutoMapper, which has taken some of the performance considerations around this problem into account.

查看更多
贼婆χ
4楼-- · 2019-07-27 11:46

Reflection isn't exactly integer addition when it comes to performance, no. But, does it matter in the case where you are using it?

The third argument to PropertyInfo.SetValue() is for setting property indexers. That is for properties that are array like. That'll be null in most cases.

I don't see anything obvious. But it does seem like the sort of thing that'll be turning up hidden little corner cases and so on for a long time. In other words, it seems like a fantastic learning exercise, which is what you wanted.

查看更多
登录 后发表回答