Improvements with reflection and generics
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:
- I am assuming that getting property information via reflection is costly? Correct?
- With
PropertyInfo.SetValue(Object, Object, Object[])
what is the last parameter for? Am I safe passing in null? - 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 cachi开发者_运维技巧ng 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; }
- 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.
- 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 the0
in that third parameter). - I'd suggest using a
ConcurrentDictionary
for yourPropertyCache
. It will help to both simplify your code and make it thread-safe.
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.
It sounds a bit like you're considering writing AutoMapper, which has taken some of the performance considerations around this problem into account.
精彩评论