【问题标题】:How to recognize a Lambda MemberExpression of type "field reference"如何识别“字段引用”类型的 Lambda MemberExpression
【发布时间】:2011-07-09 15:27:08
【问题描述】:

我必须找到一种方法,将 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 发帖

【问题讨论】:

  • “i”的值是唯一的问题吗?然后你可以简单地使用一个局部变量来让你的事情变得容易。
  • 我不是唯一使用此代码的人,不幸的是我不能强迫开发人员使用我的库在他们的循环中创建局部变量...
  • 没错,但我认为你的开发人员应该做对,如果你允许他们覆盖 c# 的默认行为,不会让他们感到困惑,即使它的编码方式错误,你的库也会使没错,他们会对不使用你的库的代码感到困惑。
  • @Akash 你是对的。我试图绕过默认的 c# 行为,以简化在循环中声明 lambda 的方式。

标签: c# .net lambda expression-trees


【解决方案1】:

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

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

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

虽然类型可能是编译器生成的,但可能还有其他原因。对我来说,这听起来不是一个非常好的主意。

您不能一开始就避免在 lambda 表达式中捕获循环变量吗?

【讨论】:

  • 如果我写t => t.id,如果id是一个字段,那么node.Member也是一个FieldInfo。这个解决方案不合适:我想找到的是,节点是对字段的隐式引用,而不是字段本身。这确实是我想要检测的“value(testExpression.Program+c__DisplayClass4).i”表达式部分。
  • @Raph:嗯,就表达式而言,它们都只是字段。您可以检查该字段是否是编译器生成的类的成员,我想...
  • 不,我打算使用我正在构建的 lib 正是这种 lambda... 你说得对:问题是要区分隐式和显式编译器生成的参数... ...
  • @Raph:鉴于 lambda 表达式确实代表捕获迭代变量,我只想将其声明为自然的副作用。 IMO,最好不要陷入这种情况而不是尝试解决它。​​
  • 我使用这些 lambdas 来提取对任何对象属性的显式委托,我需要映射子属性(如列表 4 ex),以便将它们映射到动态构建的 getter 和 setter类型。我知道这是一种非常奇怪的方法,但我别无选择。我必须处理索引属性中的属性...
猜你喜欢
  • 2022-07-20
  • 1970-01-01
  • 2020-09-21
  • 2016-02-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多