如何有效地使用GetProperties()?(涉及IT技术)

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


为什么不添加序列化器属性? - Daniel A. White
1
为什么我需要添加它? - user6011767
1
你知道在foreach中将Password属性的值设置为null了吗? - xanatos
@xanatos 是的,谢谢你 - user6011767
1个回答

3
通过记忆化其结果。将结果保存在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树在运行时生成一些代码来清理对象。这样速度会更快,但代码生成变得更慢。而且执行此操作的代码更加复杂。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接