[英]Retrieve a delegate (Action<TObject, TValue>) to the Setter of an Indexer with ExpressionTree
I'm trying to create delegates to access any Property Get & Set methods.我正在尝试创建代表来访问任何 Property Get & Set 方法。
I have found the following code (on this post: driis about deep properties ) which works really fine:我找到了以下代码(在这篇文章中: 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);
}
}
For example: when I create the setter from the Expression in parameter, I obtain my getter and setter delegates like these ones:例如:当我从 Expression in 参数创建 setter 时,我获得了我的 getter 和 setter 委托,如下所示:
get : (t => t.ID)
set : (t, value) => { t.ID = value}
My problem is with indexers like this one:我的问题是这样的索引器:
public object this[int id]
When I call with a sub property of an indexer, there is no problem.当我使用索引器的子属性调用时,没有问题。 It works fine since the indexer, internally named "Item" is accessed by reading it:它工作正常,因为通过读取它来访问内部命名为“Item”的索引器:
Extractor<MyObject>.DelegateAccessor(t => t.MySubTable[2].MyProperty)
the expression is:表达式是:
t => t.MySubTable.get_Item(2).MyProperty
But I don't find a way to get the internal setter expression.但我找不到获取内部设置器表达式的方法。 My goal is to obtain something like this:我的目标是获得这样的东西:
(t, value) => { t.MySubTable.set_Item(2, value) }
But I can't use assignment with a Lambda like this one:但我不能像这样使用 Lambda 的赋值:
(t,v) => t.SubStrings[0] = v
I get an error CS0832: An expression tree may not contain an assignment operator.我收到错误 CS0832:表达式树可能不包含赋值运算符。
Is there a way to write a Lambda Expression in order to find the "set_Item(2, value)" body in a Expression> parameter???有没有办法编写 Lambda 表达式以便在 Expression> 参数中找到“set_Item(2, value)”主体?
Thanks in advance, I know it's a hard question...提前谢谢,我知道这是一个很难的问题......
If I understand you correctly, you want a method that works exactly as the one you already have, but that also works for something like如果我对您的理解正确,您需要一种与您已有的方法完全相同的方法,但也适用于类似的方法
Extractor<MyObject>.DelegateAccessor(t => t.MySubTable[2])
If that's the case, something like this should work:如果是这样的话,这样的事情应该可以工作:
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);
}
The first part is basically copy of the method you have.第一部分基本上是您拥有的方法的副本。 The second part checks whether the expression is a call to a getter method and if it is, replaces it with call to setter method.第二部分检查表达式是否是对 getter 方法的调用,如果是,则将其替换为对 setter 方法的调用。 There is some work regarding parameters, but other than that, quite straight-forward.有一些关于参数的工作,但除此之外,非常简单。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.