简体   繁体   English

反射性能 - 创建代理(属性C#)

[英]Reflection Performance - Create Delegate (Properties C#)

I'm having performance problems with using reflection. 我在使用反射时遇到了性能问题。
So I decided to create delegates for the properties of my objects and so far got this: 所以我决定为我的对象的属性创建委托,到目前为止得到了这个:

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();
}

The results were highly satisfactory, about 30-40 times faster than using the conventional method ( PropertyInfo.GetValue (obj, null); ) 结果非常令人满意,比使用传统方法快3-40-40倍( PropertyInfo.GetValue (obj, null);

The problem is: How can I make a SetValue of a property, which works the same way? 问题是: 如何创建属性的SetValue ,其工作方式相同? Unfortunately did not get a way. 不幸的是没有办法。

I am doing so because I can not use methods with <T> because of the structure of my application. 我这样做是因为我不能使用<T>方法,因为我的应用程序的结构。

This should work for you: 这应该适合你:

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();
}

Usage: 用法:

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

With TestClass : 使用TestClass

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

Prints out: 打印出来:

foo FOO

I think you'd be better off with CreateDelegate construct if performance is the key. 如果性能是关键,我认为你最好使用CreateDelegate构造。 Since you know the signature of the method beforehand, which here is just GetGetMethod and GetSetMethod of the PropertyInfo , you can create a delegate to execute the very method with the same signature directly. 既然你知道方法的事先签名,在这里只是GetGetMethodGetSetMethod的的PropertyInfo ,您可以创建一个委托执行的方法很直接相同的签名。 Expressions would be better suited if you need to build some logic (for which you did not have a method handle) to delegates. 如果您需要为委托构建一些逻辑(您没有方法句柄),表达式将更适合。 I did some benchmarking on different routes to this problem: 我在针对这个问题的不同路线上做了一些基准测试:

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);
}

Results for about 10000000 calls - (Get, Set): 大约10000000个电话的结果 - (获取,设置):

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

GetValue-SetValue (delegate): 3600 ms, 5300 ms GetValue-SetValue(委托):3600毫秒,5300毫秒

compiled expressions: 编译表达式:

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

create delegate: 130 ms, 135 ms 创建委托:130毫秒,135毫秒

direct property call: 70 ms, 70 ms 直接财产电话:70毫秒,70毫秒

I would, in your case, write: 在你的情况下,我会写:

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;
}

So now you call: 所以现在你打电话:

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

Isn't that simpler?? 不是那么简单吗? Had written a generic class here to handle the exact thing. 在这里写了一个通用类来处理确切的事情。

Use dynamic types. 使用动态类型。 They use reflection under the hood, but they're a lot faster. 他们在引擎盖下使用反射,但它们速度要快得多。

Otherwise... 除此以外...

There are tons of free faster reflection libraries out there with permissive licenses. 有大量免费的快速反射库,其中有许可许可证。 I would link you, but there are too many, and I'm not sure which would suit you. 我会链接你,但有太多了,我不确定哪种适合你。 Just search codeplex etc. When you find something you like, try it out. 只需搜索codeplex等。当你找到喜欢的东西时,试一试。

But yeah, maybe before that, think if reflection really is the answer. 但是,也许在那之前,想想反思真的答案。 Often there are other solutions. 通常还有其他解决方案。

Edit: As Requested... 编辑:按要求...

http://geekswithblogs.net/SunnyCoder/archive/2009/06/26/c-4.0-dynamics-vs.-reflection.aspx 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://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 http://www.mssoftwareconsulting.com/msswc/blog/post/C-40-and-dynamic-performance.aspx

It's common knowledge as far as I can tell. 据我所知,这是常识。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM