我正在尝试创建委托(delegate)来访问任何 Property Get 和 Set 方法。
我发现以下代码(在这篇文章中:driis about deep properties)非常有效:
public static class Extractor<TObject> where TObject : class
{
public static DelegateAccessor<TObject, TValue> GetAccessorsDelegates<TValue>(Expression<Func<TObject, TValue>> expression)
{
Func<TObject, TValue> getter = expression.Compile();
ParameterExpression pObj = expression.Parameters[0];
ParameterExpression pValue = Expression.Parameter(typeof(TValue), "value");
BlockExpression setterBlock = Expression.Block(Expression.Assign(expression.Body, pValue));
Expression<Action<TObject, TValue>> setterExpression = Expression.Lambda<Action<TObject, TValue>>(setterBlock, pObj, pValue);
Action<TObject, TValue> setter = setterExpression.Compile();
return new DelegateAccessor<TObject, TValue>(getter,setter);
}
}
例如:当我从参数中的表达式创建 setter 时,我获得了如下这些 getter 和 setter 委托(delegate):
get : (t => t.ID)
set : (t, value) => { t.ID = value}
我的问题是像这样的索引器:
public object this[int id]
当我调用索引器的子属性时,没有问题。它工作正常,因为索引器,内部命名为“Item”,通过读取它来访问:
Extractor<MyObject>.DelegateAccessor(t => t.MySubTable[2].MyProperty)
表达式是:
t => t.MySubTable.get_Item(2).MyProperty
但我没有找到获取内部 setter 表达式的方法。我的目标是获得这样的东西:
(t, value) => { t.MySubTable.set_Item(2, value) }
但我不能像这样对 Lambda 使用赋值:
(t,v) => t.SubStrings[0] = v
我收到错误 CS0832:表达式树不能包含赋值运算符。
有没有一种方法可以编写 Lambda 表达式以便在表达式> 参数中找到“set_Item(2, value)”主体???
提前致谢,我知道这是一个很难的问题...
最佳答案
如果我没理解错的话,您想要一种与您已有的方法完全一样的方法,但它也适用于类似的东西
Extractor<MyObject>.DelegateAccessor(t => t.MySubTable[2])
如果是这样的话,像这样的东西应该可以工作:
public static DelegateAccessor<TObject, TValue> GetAccessorsDelegates<TValue>(
Expression<Func<TObject, TValue>> expression)
{
Func<TObject, TValue> getter = expression.Compile();
Action<TObject, TValue> setter = null;
ParameterExpression pValue = Expression.Parameter(typeof(TValue), "value");
ParameterExpression pObj = expression.Parameters[0];
if (expression.Body is MemberExpression)
{
Expression setterBlock = Expression.Assign(expression.Body, pValue);
Expression<Action<TObject, TValue>> setterExpression =
Expression.Lambda<Action<TObject, TValue>>(setterBlock, pObj, pValue);
setter = setterExpression.Compile();
}
else
{
var getterCall = expression.Body as MethodCallExpression;
if (getterCall != null)
{
var method = getterCall.Method;
if (method.IsSpecialName && method.Name.StartsWith("get_"))
{
var parameters = method.GetParameters()
.Select(p => p.ParameterType)
.Concat(new[] { method.ReturnType })
.ToArray();
var setterName = "set_" + method.Name.Substring(4);
var setterMethod =
method.DeclaringType.GetMethod(setterName, parameters);
var setterCall = Expression.Call(
getterCall.Object, setterMethod,
getterCall.Arguments.Concat(new[] { pValue }));
var setterExpression =
Expression.Lambda<Action<TObject, TValue>>(
setterCall, pObj, pValue);
setter = setterExpression.Compile();
}
}
}
return new DelegateAccessor<TObject, TValue>(getter, setter);
}
第一部分基本上是您拥有的方法的副本。第二部分检查表达式是否是对 getter 方法的调用,如果是,则将其替换为对 setter 方法的调用。有一些关于参数的工作,但除此之外,非常简单。
关于c# - 使用 ExpressionTree 将委托(delegate) (Action<TObject, TValue>) 检索到索引器的 Setter,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6628559/