C# 使用ExpressionTree检索索引器的Setter的委托(Action<;TObject,TValue>;)
我试图创建委托来访问任何属性Get&Set方法 我发现以下代码(在这篇文章中:)工作得非常好:C# 使用ExpressionTree检索索引器的Setter的委托(Action<;TObject,TValue>;),c#,.net,delegates,lambda,C#,.net,Delegates,Lambda,我试图创建委托来访问任何属性Get&Set方法 我发现以下代码(在这篇文章中:)工作得非常好: public static class Extractor<TObject> where TObject : class { public static DelegateAccessor<TObject, TValue> GetAccessorsDelegates<TValue>(Expression<Func<TObject, TValue&g
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);
}
}
我的问题是像这样的索引器:
public object this[int id]
当我使用索引器的子属性调用时,没有问题。它工作正常,因为内部命名为“Item”的索引器是通过读取它来访问的:
Extractor<MyObject>.DelegateAccessor(t => t.MySubTable[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])
Extractor.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);
}
publicstaticdelegateaccessor GetAccessorsDelegates(
表达式(表达式)
{
Func getter=expression.Compile();
动作设置器=null;
ParameterExpression pValue=表达式参数(typeof(TValue),“value”);
ParameterExpression pObj=表达式。参数[0];
if(expression.Body是MemberExpression)
{
表达式setterBlock=Expression.Assign(Expression.Body,pValue);
表情表达=
Lambda表达式(setterBlock,pObj,pValue);
setter=setterExpression.Compile();
}
其他的
{
var getterCall=expression.Body作为MethodCallExpression;
if(getterCall!=null)
{
var方法=getterCall.method;
if(method.IsSpecialName&&method.Name.StartsWith(“get”))
{
var parameters=method.GetParameters()
.Select(p=>p.ParameterType)
.Concat(新[]{method.ReturnType})
.ToArray();
var setterName=“set_”+method.Name.Substring(4);
变量设置法=
method.DeclaringType.GetMethod(setterName,参数);
var setterCall=Expression.Call(
getterCall.Object,setterMethod,
Concat(new[]{pValue});
变压=
Lambda(
setterCall、pObj、pValue);
setter=setterExpression.Compile();
}
}
}
返回新的DelegateAccessor(getter、setter);
}
第一部分基本上是你的方法的副本。第二部分检查表达式是否是对getter方法的调用,如果是,则将其替换为对setter方法的调用。关于参数有一些工作,但除此之外,非常简单。替换是一个非常好的解决方案,但我搜索的是一种声明Lambda表达式的方法,该表达式直接给出索引设置器。报告的错误CS0832似乎阻止直接提取对索引器的访问…为什么需要lambda表达式(而不是与委托或
表达式相对应的表达式
)。您可以这样做,但不能将这样的lambda表达式转换为表达式
。您的解决方案最终是好的,因为没有其他方法可以访问set_Item()方法。。。非常感谢你!!!
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);
}