bit*_*onk 6 c# reflection linq-expressions
我需要调用在运行时通过反射确定的属性,并以高频率调用它们.所以我正在寻找具有最佳性能的解决方案,这意味着我可能会避免反思.我在考虑将属性访问器存储为列表中的Func和Action委托,然后调用它们.
private readonly Dictionary<string, Tuple<Func<object>, Action<object>>> dataProperties =
new Dictionary<string, Tuple<Func<object>, Action<object>>>();
private void BuildDataProperties()
{
foreach (var keyValuePair in this.GetType()
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.Where(p => p.Name.StartsWith("Data"))
.Select(
p =>
new KeyValuePair<string, Tuple<Func<object>, Action<object>>>(
p.Name,
Tuple.Create(this.GetGetter(p), this.GetSetter(p)))))
{
this.dataProperties.Add(keyValuePair.Key, keyValuePair.Value);
}
}
Run Code Online (Sandbox Code Playgroud)
现在的问题是,如何将访问器分离为Func和Action为以后的调用进行分类?
仍然使用反射进行调用的天真实现如下所示:
private Func<object> GetGetter(PropertyInfo info)
{
// 'this' is the owner of the property
return () => info.GetValue(this);
}
private Action<object> GetSetter(PropertyInfo info)
{
// 'this' is the owner of the property
return v => info.SetValue(this, v);
}
Run Code Online (Sandbox Code Playgroud)
如何在没有refelections的情况下实现上述方法.表达式是最快的方式吗?我试过使用这样的表达式:
private Func<object> GetGetter(PropertyInfo info)
{
// 'this' is the owner of the property
return
Expression.Lambda<Func<object>>(
Expression.Convert(Expression.Call(Expression.Constant(this), info.GetGetMethod()), typeof(object)))
.Compile();
}
private Action<object> GetSetter(PropertyInfo info)
{
// 'this' is the owner of the property
var method = info.GetSetMethod();
var parameterType = method.GetParameters().First().ParameterType;
var parameter = Expression.Parameter(parameterType, "value");
var methodCall = Expression.Call(Expression.Constant(this), method, parameter);
// ArgumentException: ParameterExpression of type 'System.Boolean' cannot be used for delegate parameter of type 'System.Object'
return Expression.Lambda<Action<object>>(methodCall, parameter).Compile();
}
Run Code Online (Sandbox Code Playgroud)
但是,GetSetter
如果属性的类型不完全是类型,那么我的最后一行得到以下的excpetion System.Object
:
ArgumentException:类型为'System.Boolean'的ParameterExpression不能用于'System.Object'类型的委托参数
小智 5
这是我的方法,效果很好。
但我不知道它的性能。
public static Func<object, object> GenerateGetterFunc(this PropertyInfo pi)
{
//p=> ((pi.DeclaringType)p).<pi>
var expParamPo = Expression.Parameter(typeof(object), "p");
var expParamPc = Expression.Convert(expParamPo,pi.DeclaringType);
var expMma = Expression.MakeMemberAccess(
expParamPc
, pi
);
var expMmac = Expression.Convert(expMma, typeof(object));
var exp = Expression.Lambda<Func<object, object>>(expMmac, expParamPo);
return exp.Compile();
}
public static Action<object, object> GenerateSetterAction(this PropertyInfo pi)
{
//p=> ((pi.DeclaringType)p).<pi>=(pi.PropertyType)v
var expParamPo = Expression.Parameter(typeof(object), "p");
var expParamPc = Expression.Convert(expParamPo,pi.DeclaringType);
var expParamV = Expression.Parameter(typeof(object), "v");
var expParamVc = Expression.Convert(expParamV, pi.PropertyType);
var expMma = Expression.Call(
expParamPc
, pi.GetSetMethod()
, expParamVc
);
var exp = Expression.Lambda<Action<object, object>>(expMma, expParamPo, expParamV);
return exp.Compile();
}
Run Code Online (Sandbox Code Playgroud)
我认为您需要做的是将 Lamda 作为正确的类型返回,并object
作为参数,但是在调用 setter 之前在表达式中将表达式转换为正确的类型:
private Action<object> GetSetter(PropertyInfo info)
{
// 'this' is the owner of the property
var method = info.GetSetMethod();
var parameterType = method.GetParameters().First().ParameterType;
// have the parameter itself be of type "object"
var parameter = Expression.Parameter(typeof(object), "value");
// but convert to the correct type before calling the setter
var methodCall = Expression.Call(Expression.Constant(this), method,
Expression.Convert(parameter,parameterType));
return Expression.Lambda<Action<object>>(methodCall, parameter).Compile();
}
Run Code Online (Sandbox Code Playgroud)
实例: http: //rextester.com/HWVX33724