2016-03-11 3 views
4
public object GetObjectToSerialize(object value, Type targetType) 
{ 
     var allProperties = value.GetType().GetProperties(); 

     var passwordProperties = allProperties.Where(p => p.PropertyType == typeof(string)) 
              .Where(p => p.Name.Contains("Password")) 
              .ToList(); 

     var passwordWithoutEncryptedAttribute = passwordProperties 
       .Where(p => !p.GetCustomAttributes(typeof(EncryptedConfigurationItemAttribute), false).Any()); 

     if (passwordWithoutEncryptedAttribute.Any()) 
     { 
      throw new InvalidOperationException(SafeFormatter.Format(BackgroundJobsLocalization.Culture, BackgroundJobsLocalization.PasswordWithoutEncryptedAttribute)); 
     } 

     foreach (var property in passwordProperties) 
     { 
      property.SetValue(value, null, null); 
     } 

     return value; 
} 

Я использую этот метод довольно часто. Как я могу его оптимизировать? Поскольку, как я знал, value.GetType().GetProperties(); работает рекурсивно (для базового объекта, затем для свойств базового объекта, затем каждого свойства свойств базового объекта и т. Д.)Как эффективно работать с GetProperties()?

+0

Почему вы не добавляете атрибуты сериализатора? –

+1

Зачем его добавлять? –

+1

Вы знаете, что вы устанавливаете значение 'null' значения' Password' в 'foreach', правильно? – xanatos

ответ

3

К memoizing его результат. Сохраните результат в Dictionary<Type, PropertyInfo[]>, затем в начале функции проверьте, вы уже рассчитали его. Если да, верните значение Dictionary<,>. Если вы хотите сделать его потокобезопасным, используйте ConcurrentDictionary<Type, PropertyInfo[]>.

Что-то вроде:

//private static readonly Dictionary<Type, PropertyInfo[]> PasswordProperties = new Dictionary<Type, PropertyInfo[]>(); 
private static readonly ConcurrentDictionary<Type, PropertyInfo[]> PasswordProperties = new ConcurrentDictionary<Type, PropertyInfo[]>(); 

public static object GetObjectToSerialize(object value, Type targetType) { 
    Type type = value.GetType(); 

    PropertyInfo[] properties; 

    if (!PasswordProperties.TryGetValue(type, out properties)) 
    { 
     properties = type.GetProperties() 
         .Where(p => p.PropertyType == typeof(string)) 
         .Where(p => p.Name.Contains("Password")) 
         .ToArray(); 

     var passwordWithoutEncryptedAttribute = properties 
        .Where(p => !p.GetCustomAttributes(typeof(EncryptedConfigurationItemAttribute), false).Any()); 

     if (passwordWithoutEncryptedAttribute.Any()) { 
      throw new InvalidOperationException(); // SafeFormatter.Format(BackgroundJobsLocalization.Culture, BackgroundJobsLocalization.PasswordWithoutEncryptedAttribute)); 
     } 

     PasswordProperties[type] = properties; 
    } 

    foreach (var property in properties) 
    { 
     property.SetValue(value, null, null); 
    } 

    return value; 
} 

Если у вас есть доступ к типу value во время компиляции, это оптимизируемое по-другому, по memoizing внутри поля статического универсального класса:

public static class ObjectHelper 
{ 
    public static T GetObjectToSerialize<T>(T value) 
    { 
     foreach (var property in ObjectHelperInner<T>.Properties) 
     { 
      property.SetValue(value, null, null); 
     } 

     return value; 
    } 

    private static class ObjectHelperInner<T> 
    { 
     public static readonly PropertyInfo[] Properties; 

     static ObjectHelperInner() 
     { 
      PropertyInfo[] properties = typeof(T).GetProperties() 
                .Where(p => p.PropertyType == typeof(string)) 
                .Where(p => p.Name.Contains("Password")) 
                .ToArray(); 

      var passwordWithoutEncryptedAttribute = properties 
         .Where(p => !p.GetCustomAttributes(typeof(EncryptedConfigurationItemAttribute), false).Any()); 

      if (passwordWithoutEncryptedAttribute.Any()) { 
       throw new InvalidOperationException(); // SafeFormatter.Format(BackgroundJobsLocalization.Culture, BackgroundJobsLocalization.PasswordWithoutEncryptedAttribute)); 
      } 

      Properties = properties; 
     } 
    } 
} 

Это вторая версия кода не работать, если у вас есть:

object obj = something; 
ObjectHelper.GetObjectToSerialize(obj); 

Это будет работать только если у вас есть:

SomeConcreteType obj = something; 
ObjectHelper.GetObjectToSerialize(obj); 

Другим возможным решением является создание (через Expression деревьев) код во время выполнения, чтобы очистить объект. Он становится намного быстрее, но генерация кода становится намного медленнее. И код для этого гораздо сложнее.

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