我必须找到一种方法来替换lambda表达式中的隐式字段引用,并使用它的实际值。例如:
Expression<Func<TestObject, String>> exp = null;
for (int i = 0; i < 1; i++)
{
exp = t => t.SubObjs[i].TestSTR;
}
Func<TestObject, String> testFunc = exp.Compile();
String testValue = testFunc(myObj);
检查代表时,您可以看到:
{t => t.SubObjs.get_Item(value(testExpression.Program+<>c__DisplayClass4).i).TestSTR}
在for循环外调用委托时,通过引用解决“i”的值。但是“i”已经改变,因为它是最后一次迭代(“i”== 1而不是0)。
所以我构建了一个特定的ExpressionVisitor,以便用ConstantExpression替换相应的节点:
public class ExpressionParameterSolver : ExpressionVisitor
{
protected override Expression VisitMember(MemberExpression node)
{
if (node.ToString().StartsWith("value(") && node.NodeType == ExpressionType.MemberAccess)
{
var index = Expression.Lambda(node).Compile().DynamicInvoke(null);
return Expression.Constant(index, index.GetType());
}
return base.VisitMember(node);
}
}
我没有找到除.StartsWith(“value(”)以外的方法来检测当前节点是对字段的引用...这种节点继承自FieldExpression但是这个类是内部的,我不确定FieldExpression是否只封装了我认为是“隐式字段引用”的内容。
有没有一种方法(属性或方法)明确知道MemberExpression节点是一个隐式字段引用???
提前致谢!!!
感谢this stakx帖子
答案 0 :(得分:4)
只需从表达式中获取Member
属性,看看它是FieldInfo
...
如果您只希望它适用于编译器生成类的情况,您可以使用
if (expression.Member is FieldInfo &&
expression.Member
.DeclaringType
.IsDefined(typeof(CompilerGeneratedAttribute), false))
{
....
}
可能还有其他原因导致类型可能是编译器生成的。这对我来说听起来不是一个好主意。
难道你不能避免在lambda表达式中捕获循环变量以开始吗?