我在使用反射方面遇到了性能问题 所以我决定为我的对象的属性创建委托,到目前为止得到了这个:
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();
}
结果非常令人满意,比使用传统方法(PropertyInfo.GetValue (obj, null);
)快30-40倍
问题是:如何制作SetValue
的财产,其运作方式相同?不幸的是没有办法。
我这样做是因为我的申请结构不能使用<T>
的方法。
答案 0 :(得分:17)
这应该适合你:
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; }
}
打印出来:
FOO
答案 1 :(得分:13)
如果性能是关键,我认为你最好使用CreateDelegate
构造。由于您事先知道了方法的签名(这里只是GetGetMethod
的{{1}}和GetSetMethod
),因此您可以创建一个委托来直接执行具有相同签名的方法。如果您需要为委托构建一些逻辑(您没有方法句柄),表达式将更适合。我在针对这个问题的不同路线上做了一些基准测试:
PropertyInfo
大约10000000个电话的结果 - (获取,设置):
GetValue-SetValue(直接):3800毫秒,5500毫秒
GetValue-SetValue(委托):3600毫秒,5300毫秒
编译表达式:
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); }
创建委托:130毫秒,135毫秒
直接财产电话:70毫秒,70毫秒
在你的情况下,我会写:
Get: Expression.Property: 280 ms
Expression.Call: 280 ms
direct compile: 280 ms
Set: 300 ms
所以现在你打电话:
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;
}
不是那么简单吗?曾写过一个通用的类here来处理确切的事情。
答案 2 :(得分:2)
使用动态类型。他们在引擎盖下使用反射,但它们很多更快。
...否则
有许多免费的快速反射库,其中有许可许可证。我会链接你,但有太多了,我不确定哪种适合你。只需搜索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
据我所知,这是常识。