如何识别“字段引用”类型的Lambda MemberExpression

时间:2011-07-09 15:27:09

标签: c# .net lambda expression-trees

我必须找到一种方法来替换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帖子

1 个答案:

答案 0 :(得分:4)

只需从表达式中获取Member属性,看看它是FieldInfo ...

如果您只希望它适用于编译器生成类的情况,您可以使用

if (expression.Member is FieldInfo && 
    expression.Member
              .DeclaringType
              .IsDefined(typeof(CompilerGeneratedAttribute), false))
{
    ....
}

可能还有其他原因导致类型可能是编译器生成的。这对我来说听起来不是一个好主意。

难道你不能避免在lambda表达式中捕获循环变量以开始吗?