1

我正在尝试提高下面代码中的性能,并且有点知道如何但不确定哪种方法是最好的。第一次命中需要更长的时间,但随后的命中应该更快。现在,我可以缓存 T(其中 T 是一个类),然后检查缓存以查看“T”是否存在,如果存在 - 继续获取其相关信息(NamedArguments)并遍历每个 NamedArguments,最后如果条件匹配,继续设置当前属性的值。

我只是想让它更有效率和性能。有任何想法吗?

var myProps = typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static).Where(prop => Attribute.IsDefined(prop, typeof(MyCustomAttribute)) && prop.CanWrite && prop.GetSetMethod() != null);

foreach (var currentProperty in myProps)
{
    foreach (var currentAttributeForProperty in currentProperty.GetCustomAttributesData())
    {
        foreach (var currentNamedArgument in currentAttributeForProperty.NamedArguments)
        {
            if (string.Equals(currentNamedArgument.MemberInfo.Name, "PropName", StringComparison.OrdinalIgnoreCase))
            {
                currentAttribParamValue = currentNamedArgument.TypedValue.Value == null ? null : currentNamedArgument.TypedValue.Value.ToString();

                // read the reader for the currentAttribute value
                if (reader.DoesFieldExist(currentAttribParamValue))
                {
                    var dbRecordValue = reader[currentAttribParamValue] == DBNull.Value ? null : reader[currentAttribParamValue];

                    // set it in the property
                    currentProperty.SetValue(val, dbRecordValue, null);
                }
                break;
            }
        }
    }
}
4

4 回答 4

4

DynamicMethods 或 ExpressionTrees 将比反射快得多。您可以为某个类型构建所有属性 getter/setter 的缓存,然后将该信息缓存在 a Dictionary(or ConcurrentDictionary) 中,并将 type 作为键。

流动

  • 发现类型信息(例如在应用启动时)。
  • 为每个属性编译动态方法(一次执行所有属性)。
  • 将这些方法存储在元数据类中(示例如下)。
  • 在某处缓存元数据(即使是静态字段也可以,只要访问是同步的)。使用类型作为键。
  • 在需要时获取该类型的元数据。
  • 找到合适的 getter/setter。
  • 调用,传递您希望对其执行操作的实例。

// Metadata for a type
public sealed class TypeMetadata<T> {

    // The compiled getters for the type; the property name is the key
    public Dictionary<string, Func<T, object>> Getters {
        get;
        set;
    }

    // The compiled setters for the type; the property name is the key
    public Dictionary<string, Action<T, object>> Setters {
        get;
        set;
    }
}

// rough invocation flow
var type = typeof( T);
var metadata = _cache[type];

var propertyName = "MyProperty";
var setter = metadata[propertyName];

var instance = new T();
var value = 12345;
setter( instance, value );

示例二传手

摘自动态方法实现(关于该主题的好文章)。

我不能保证这个确切的代码有效,但我自己编写了非常相似的代码。如果您对 IL 不满意,请务必考虑使用表达式树。

public static LateBoundPropertySet CreateSet(PropertyInfo property)
{
    var method = new DynamicMethod("Set" + property.Name, null, new[] { typeof(object), typeof(object) }, true);
    var gen = method.GetILGenerator();

    var sourceType = property.DeclaringType;
    var setter = property.GetSetMethod(true);

    gen.Emit(OpCodes.Ldarg_0); // Load input to stack
    gen.Emit(OpCodes.Castclass, sourceType); // Cast to source type
    gen.Emit(OpCodes.Ldarg_1); // Load value to stack
    gen.Emit(OpCodes.Unbox_Any, property.PropertyType); // Unbox the value to its proper value type
    gen.Emit(OpCodes.Callvirt, setter); // Call the setter method
    gen.Emit(OpCodes.Ret);

    var result = (LateBoundPropertySet)method.CreateDelegate(typeof(LateBoundPropertySet));

    return result;
}

*根据我的经验,快 25-100 倍

于 2013-03-04T19:36:26.650 回答
2

众所周知,反射在循环中的速度很慢,因此某种缓存可能会有所帮助。但是要决定缓存什么,你应该测量. 俗话说:“过早的优化是万恶之源”;您应该确保您确实需要优化以及具体要优化什么。

对于更具体的建议,属性是在编译时附加的,因此您可以缓存一个类型和它的 propertyInfos 列表。

于 2013-03-04T19:36:37.443 回答
1

我曾经也遇到过类似的问题 - 反射非常缓慢。我用缓存,像你计划的一样,性能增长10倍以上。它再也不会成为性能的瓶颈。

于 2013-03-04T19:36:18.430 回答
0

在为遇到的每种类型缓存“执行计划”之前,我已经创建了类似的逻辑。后续运行肯定会更快,但您必须分析您的场景以查看是否值得额外的代码复杂性和内存使用。

于 2013-03-04T19:33:35.370 回答