reflection性能 – 创建代理(属性C#)

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

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 BuildGetAccessor(MethodInfo method) { var obj = Expression.Parameter(typeof(object), "o"); Expression<Func> expr = Expression.Lambda<Func>( Expression.Convert( Expression.Call( Expression.Convert(obj, method.DeclaringType), method), typeof(object)), obj); return expr.Compile(); } 

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

问题是: 如何制作属性的SetValue ,其工作方式相同? 不幸的是没有办法。

我这样做是因为我不能使用方法,因为我的应用程序的结构。

这应该适合你:

 static Action BuildSetAccessor(MethodInfo method) { var obj = Expression.Parameter(typeof(object), "o"); var value = Expression.Parameter(typeof(object)); Expression> expr = Expression.Lambda>( 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; } } 

打印出来:

FOO

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

 Func Getter; Action Setter; PropertyInfo Property; public void Initialize(Expression> 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>(Expression.Property(inst, Property), inst).Compile(); //var inst = Expression.Parameter(typeof(S)); //Getter = Expression.Lambda>(Expression.Call(inst, Property.GetGetMethod()), inst).Compile(); //Getter = (Func)Delegate.CreateDelegate(typeof(Func), 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>(Expression.Call(inst, Property.GetSetMethod(), val), // inst, val).Compile(); //Setter = (Action)Delegate.CreateDelegate(typeof(Action), 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毫秒

GetValue-SetValue(委托):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 BuildGetAccessor(Expression> propertySelector) { return propertySelector.GetPropertyInfo().GetGetMethod().CreateDelegate>(); } public static Action BuildSetAccessor(Expression> propertySelector) { return propertySelector.GetPropertyInfo().GetSetMethod().CreateDelegate>(); } // a generic extension for CreateDelegate public static T CreateDelegate(this MethodInfo method) where T : class { return Delegate.CreateDelegate(typeof(T), method) as T; } public static PropertyInfo GetPropertyInfo(this Expression> 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); 

不是那么简单吗? 在这里写了一个通用类来处理确切的事情。

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

除此以外…

有许多免费更快的reflection库,其中有许可许可证。 我会链接你,但有太多了,我不确定哪种适合你。 只需搜索codeplex等。当你找到喜欢的东西时,试一试。

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

编辑:如要求的……

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

据我所知,这是常识。