鉴于:
FieldInfo field = <some valid string field on type T>;
ParameterExpression targetExp = Expression.Parameter(typeof(T), "target");
ParameterExpression valueExp = Expression.Parameter(typeof(string), "value");
Run Code Online (Sandbox Code Playgroud)
如何编译lambda表达式以将"target"参数上的字段设置为"value"?
我创建了将属性lambda转换为委托的方法:
public static Delegate MakeGetter<T>(Expression<Func<T>> propertyLambda)
{
var result = Expression.Lambda(propertyLambda.Body).Compile();
return result;
}
public static Delegate MakeSetter<T>(Expression<Action<T>> propertyLambda)
{
var result = Expression.Lambda(propertyLambda.Body).Compile();
return result;
}
Run Code Online (Sandbox Code Playgroud)
这些工作:
Delegate getter = MakeGetter(() => SomeClass.SomeProperty);
object o = getter.DynamicInvoke();
Delegate getter = MakeGetter(() => someObject.SomeProperty);
object o = getter.DynamicInvoke();
Run Code Online (Sandbox Code Playgroud)
但这些不会编译:
Delegate setter = MakeSetter(() => SomeClass.SomeProperty);
setter.DynamicInvoke(new object[]{propValue});
Delegate setter = MakeSetter(() => someObject.SomeProperty);
setter.DynamicInvoke(new object[]{propValue});
Run Code Online (Sandbox Code Playgroud)
MakeSetter行失败,"无法根据用法推断出类型参数.请尝试明确指定类型参数."
我正在尝试做什么?提前致谢.
我在使用反射时遇到了性能问题.
所以我决定为我的对象的属性创建委托,到目前为止得到了这个:
TestClass cwp = new TestClass();
var propertyInt = typeof(TestClass).GetProperties().Single(obj => obj.Name == "AnyValue");
var access = BuildGetAccessor(propertyInt.GetGetMethod());
var result = access(cwp);
Run Code Online (Sandbox Code Playgroud)
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();
}
Run Code Online (Sandbox Code Playgroud)
结果非常令人满意,比使用传统方法快30-40倍(PropertyInfo.GetValue (obj, null);)
问题是:我怎样才能创建SetValue一个属性相同的属性?不幸的是没有办法.
我这样做是因为我不能使用方法,<T>因为我的应用程序的结构.
所以我有一些代码在对象上设置属性.此代码来自我们在单元测试中使用的内部验证类.所以代码可能会提供类似的东西
private static void SetDeepValue(object targetObject, Expression<Func<string>> propertyToSet, object valueToSet)
{
var underlyingProperty = ((PropertyInfo)((MemberExpression)propertyToSet.Body).Member);
underlyingProperty.SetValue(targetObject, valueToSet);
}
Run Code Online (Sandbox Code Playgroud)
此代码在单元测试类型环境中使用,然后我们可以在其中进行调用
foreach (string currentTestCaseValue in TestCaseSets)
{
BusinessObject myCustomer = new BusinessObject();
SetDeepValue(myCustomer, ()=>myCustomer.FirstName,currentTestCaseValue);
ValidateBusinessRules(myCustomer);
}
Run Code Online (Sandbox Code Playgroud)
(为简洁/复杂而简化的代码)
但是,现在,由于一些重构,我们留下了类似的东西:
foreach (string currentTestCaseValue in TestCaseSets)
{
BusinessObject myCustomer = new BusinessObject();
SetDeepValue(myCustomer, ()=>myCustomer.NameInfo.First,currentTestCaseValue);
ValidateBusinessRules(myCustomer);
}
Run Code Online (Sandbox Code Playgroud)
当此代码运行时,我们收到错误:
对象与目标类型不匹配.
我怀疑它试图打电话First给BusinessObject,而不是NameInfo.如何修改我的代码来处理这个'嵌套'的情况?
c# ×4
lambda ×2
reflection ×2
.net ×1
action ×1
delegates ×1
expression ×1
linq ×1
properties ×1
setvalue ×1