2013-11-16 4 views
2

У меня есть следующий метод, который отображает исходный объект на дублирующий объект назначения. Однако только определенные свойства, помеченные определенным атрибутом, должны отображаться на новый объект.Может ли мое пользовательское сопоставление использовать отражение быстрее?

Мой картографа в настоящее время выглядит следующим образом:

public static class BaseObjectExtensions 
{ 
    private static readonly Dictionary<string, Attribute[]> AttributeCache = new Dictionary<string, Attribute[]>(); 
    private static readonly Dictionary<string, PropertyInfo[]> PropertyCache = new Dictionary<string, PropertyInfo[]>(); 

    public static void Map(this IBaseObject destination, IBaseObject source) 
    { 
     if (source == null) 
     { 
      return; 
     } 

     var t = source.GetType(); 
     PropertyInfo[] properties; 
     lock (PropertyCache) 
     { 
      if (!PropertyCache.TryGetValue(t.FullName, out properties)) 
      { 
       properties = t.GetProperties(); 
       PropertyCache.Add(t.FullName, properties); 
      } 
     } 

     lock (AttributeCache) 
     { 
      foreach (PropertyInfo prop in properties) 
      { 
       Attribute[] attrs; 
       string k = t.FullName + prop; 
       if (!AttributeCache.TryGetValue(k, out attrs)) 
       { 
        attrs = Attribute.GetCustomAttributes(prop); 
        AttributeCache.Add(k, attrs); 
       } 

       if (attrs.OfType<DatabaseMap>().Any()) 
       { 
        prop.SetValue(destination, prop.GetValue(source)); 
       } 
      } 
     } 
    } 
} 

Эта карта может использоваться либо на один элемент или набор элементов. Я заметил узкое место в производительности, поэтому после многих исследований я добавил в два кэша. Времена являются для больших коллекций предметов:

  • Без кэша отражения: 26.6 секунд
  • с кэшем отражения (ConcurrentDictionary): 31 секунд
  • с кэшем отражения (замок): 4 секунды

Ускорение драматично, но я думаю, что все еще может быть лучше. После многого чтения я нашел такие вещи, как FastInvoke и another FastInvoke, но, похоже, не применил их к тому, что я пытаюсь выполнить.

Есть ли что-нибудь еще, что я могу сделать, чтобы ускорить это?

ответ

2

Я думаю, что для наилучшей производительности можно скомпилировать картограф с помощью Reflection.Emit, или использовать один из уже существующих: Emit mapper vs valueinjecter or automapper performance

+0

Святое дерьмо EmitMapper быстро! Теперь в миллисекундах. – Dylan

2

Вы могли бы попробовать это,

, а не обрабатывать все свойства, в свою очередь, а затем проверку на наличие атрибута - просто получить свойства, которые имеют свой атрибут:

var props = from p in this.GetType().GetProperties() 
      let attr = p.GetCustomAttributes(typeof(DatabaseMap), true) 
      where attr.Length == 1 
      select new { Property = p, Attribute = attr.First() as DatabaseMap}; 

в этот момент вы только те свойства в объекте, которые отмечены вашим атрибутом.

+0

Я попытался это и удалил свой кэш атрибутов. Результат операции выше затем кэшируется. Улучшение скорости составило от 4 секунд до 1,4 секунды. – Dylan

Смежные вопросы