如何有效地使用GetProperties()?

时间:2016-03-11 13:33:04

标签: c#

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();递归地工作(对于基础对象,然后是基础对象属性,然后是基础对象属性的每个属性等)

1 个答案:

答案 0 :(得分: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的类型,则可以通过在静态泛型类的字段内进行记忆来以另一种方式进行优化:

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树)一些代码来清理对象。它变得更快,但代码生成变得慢得多。并且执行它的代码要复杂得多。