我需要通过反射在运行时调用属性,并且这些属性的调用频率很高。因此,我正在寻找性能最佳的解决方案,这意味着我可能会避免使用反射。我想将属性访问器存储为“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);
}
}
现在的问题是,我如何获取访问器委托作为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);
}
我该如何在不使用反射的情况下实现上述方法?表达式是否是最快的方法?我尝试过像这样使用表达式:
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();
}
但是,如果属性的类型不恰好为
System.Object
,则在GetSetter
的最后一行会出现以下异常:
ArgumentException: ParameterExpression of type 'System.Boolean' cannot be used for delegate parameter of type 'System.Object'
Func<object>
和Action<object>
而不是适当的类型,例如Func<bool>
和Action<bool>
? - Jon SkeetFunc<object>
和Action<object>
而不是适当的类型。 - bitbonk