反射性能 - 创建委托(属性 C#)

本文关键字:属性 反射性 性能 创建 反射 | 更新日期: 2023-09-27 18:35:42

我在使用反射时遇到了性能问题。
所以我决定为我的对象的属性创建委托,到目前为止得到了这个:

TestClass cwp = new TestClass();
var propertyInt = typeof(TestClass).GetProperties().Single(obj => obj.Name == "AnyValue");
var access = BuildGetAccessor(propertyInt.GetGetMethod());
var result = access(cwp);
static Func<object, object> BuildGetAccessor(MethodInfo method)
{
    var obj = Expression.Parameter(typeof(object), "o");
    Expression<Func<object, object>> expr =
        Expression.Lambda<Func<object, object>>(
            Expression.Convert(
                Expression.Call(
                    Expression.Convert(obj, method.DeclaringType),
                    method),
                typeof(object)),
            obj);
    return expr.Compile();
}

结果非常令人满意,比使用传统方法快约30-40倍(PropertyInfo.GetValue (obj, null);

问题是:我怎样才能对一个工作方式相同的属性进行SetValue?不幸的是没有得到办法。

我这样做是因为由于应用程序的结构,我无法将方法与<T>一起使用。

反射性能 - 创建委托(属性 C#)

这应该适合您:

static Action<object, object> BuildSetAccessor(MethodInfo method)
{
    var obj = Expression.Parameter(typeof(object), "o");
    var value = Expression.Parameter(typeof(object));
    Expression<Action<object, object>> expr =
        Expression.Lambda<Action<object, object>>(
            Expression.Call(
                Expression.Convert(obj, method.DeclaringType),
                method,
                Expression.Convert(value, method.GetParameters()[0].ParameterType)),
            obj,
            value);
    return expr.Compile();
}

用法:

var accessor = BuildSetAccessor(typeof(TestClass).GetProperty("MyProperty").GetSetMethod());
var instance = new TestClass();
accessor(instance, "foo");
Console.WriteLine(instance.MyProperty);

TestClass

public class TestClass 
{
    public string MyProperty { get; set; }
}

打印输出:

噗��

我认为如果性能是关键,你最好使用CreateDelegate结构。由于您事先知道该方法的签名,这里只是PropertyInfoGetGetMethodGetSetMethod,因此您可以创建一个委托来直接执行具有相同签名的方法。如果需要为委托构建一些逻辑(没有方法句柄),则表达式将更适合。我对这个问题的不同路线进行了一些基准测试:

Func<S, T> Getter;
Action<S, T> Setter;
PropertyInfo Property;
public void Initialize(Expression<Func<S, T>> propertySelector)
{
    var body = propertySelector.Body as MemberExpression;
    if (body == null)
        throw new MissingMemberException("something went wrong");
    Property = body.Member as PropertyInfo;

    //approaches:
    //Getter = s => (T)Property.GetValue(s, null);
    //Getter = memberSelector.Compile();
    //ParameterExpression inst = Expression.Parameter(typeof(S));
    //Getter = Expression.Lambda<Func<S, T>>(Expression.Property(inst, Property), inst).Compile();
    //var inst = Expression.Parameter(typeof(S));
    //Getter = Expression.Lambda<Func<S, T>>(Expression.Call(inst, Property.GetGetMethod()), inst).Compile();
    //Getter = (Func<S, T>)Delegate.CreateDelegate(typeof(Func<S, T>), Property.GetGetMethod());

    //Setter = (s, t) => Property.SetValue(s, t, null);
    //var val = Expression.Parameter(typeof(T));
    //var inst = Expression.Parameter(typeof(S));
    //Setter = Expression.Lambda<Action<S, T>>(Expression.Call(inst, Property.GetSetMethod(), val),
    //                                         inst, val).Compile();
    //Setter = (Action<S, T>)Delegate.CreateDelegate(typeof(Action<S, T>), Property.GetSetMethod());
}

//Actual calls (tested under loop):
public T Get(S instance)
{
    //direct invocation:
    //return (T)Property.GetValue(instance, null);
   //calling the delegate:
   //return Getter(instance);
}
public void Set(S instance, T value)
{
    //direct invocation:
    //Property.SetValue(instance, value, null);
   //calling the delegate:
   //Setter(instance, value);
}

大约 10000000 次调用的结果 - (获取、设置):

GetValue-SetValue (直接): 3800 毫秒, 5500 毫秒

获取值集值(委托):3600 毫秒、5300 毫秒

编译的表达式:

   Get: Expression.Property: 280 ms
        Expression.Call: 280 ms
        direct compile: 280 ms
   Set: 300 ms

创建委托:130 毫秒、135 毫秒

直接属性调用:70 毫秒、70 毫秒

在你的情况下,我会写:

public static Func<S, T> BuildGetAccessor<S, T>(Expression<Func<S, T>> propertySelector)
{
    return propertySelector.GetPropertyInfo().GetGetMethod().CreateDelegate<Func<S, T>>();
}
public static Action<S, T> BuildSetAccessor<S, T>(Expression<Func<S, T>> propertySelector)
{
    return propertySelector.GetPropertyInfo().GetSetMethod().CreateDelegate<Action<S, T>>();
}
// a generic extension for CreateDelegate
public static T CreateDelegate<T>(this MethodInfo method) where T : class
{
    return Delegate.CreateDelegate(typeof(T), method) as T;
}
public static PropertyInfo GetPropertyInfo<S, T>(this Expression<Func<S, T>> propertySelector)
{
    var body = propertySelector.Body as MemberExpression;
    if (body == null)
        throw new MissingMemberException("something went wrong");
    return body.Member as PropertyInfo;
}

所以现在你打电话:

TestClass cwp = new TestClass();
var access = BuildGetAccessor((TestClass t) => t.AnyValue);
var result = access(cwp);

这不是更简单吗??在这里编写了一个泛型类来处理确切的事情。

使用动态类型。他们在引擎盖下使用反射,但它们要快得多

否则。。。

有大量免费的快速反射库,具有宽松的许可证。我会链接你,但太多了,我不确定哪个适合你。只需搜索代码复合体等。当你找到你喜欢的东西时,试试看。

但是,是的,也许在此之前,想想反思是否真的答案。通常还有其他解决方案。

编辑:根据要求...


http://geekswithblogs.net/SunnyCoder/archive/2009/06/26/c-4.0-dynamics-vs.-reflection.aspx
http://theburningmonk.com/2010/09/performance-test-dynamic-method-invocation-in-csharp-4/
http://www.mssoftwareconsulting.com/msswc/blog/post/C-40-and-dynamic-performance.aspx

我所知,这是常识。