【问题标题】:force Expression<> to evaluate local variables强制 Expression<> 计算局部变量
【发布时间】:2012-10-04 19:27:47
【问题描述】:

我在 LinqPad 中有这样的东西

void Main()
{
    var t1 = DateTimeOffset.Parse("10/1/2012");

    int? n1 = 1;

    Expression<Func<Sample,bool>> x1 = ud => 
        (ud.Date == t1 && ud.Number == n1);

    x1.ToString().Dump();
}

class Sample
{
    public int? Number{set;get;}
    public DateTimeOffset Date{set;get;}
}

输出

ud => ((ud.Date == value(UserQuery+c_DisplayClass0).t1) AndAlso (ud.Number == value(UserQuery+c_DisplayClass0).n1))

是否有任何可能的方法来保留变量但让它输出如下内容:

ud => ((ud.Date == Parse("10/1/2012")) AndAlso (ud.Number == 转换(1)))

【问题讨论】:

  • 我可以检查一下:您的目标是删除捕获类 / MemberExpression 吗?
  • 这个想法是让 lambda 输出可读,仅此而已。

标签: c# .net lambda expression-trees


【解决方案1】:

我们来了;先输出:

ud => ((ud.Date == 10/01/2012 00:00:00 +00:00) AndAlso (ud.Number == 1))

这将永远不会输出Parse(...),因为您的表达式不包含解析:当您将其放入 lambda 时,您已经对其进行了评估。

另请注意,这会处理一级捕获的变量。对于更复杂(嵌套)的捕获上下文,您必须递归地从捕获类中获取值:

using System;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
static class Program
{
    static void Main()
    {
        var t1 = DateTimeOffset.Parse("10/1/2012");

        int? n1 = 1;

        Expression<Func<Sample, bool>> x1 = ud =>
            (ud.Date == t1 && ud.Number == n1);

        var sanitized = (Expression<Func<Sample, bool>>)
            new Literalizer().Visit(x1);

        Console.WriteLine(sanitized.ToString());
    }
}

class Literalizer : ExpressionVisitor
{
    protected override Expression VisitMember(MemberExpression node)
    {
        if(node.Member.DeclaringType.IsDefined(typeof(CompilerGeneratedAttribute), false)
            && node.Expression.NodeType == ExpressionType.Constant)
        {
            object target = ((ConstantExpression)node.Expression).Value, value;
            switch (node.Member.MemberType)
            {
                case MemberTypes.Property:
                    value = ((PropertyInfo)node.Member).GetValue(target, null);
                    break;
                case MemberTypes.Field:
                    value = ((FieldInfo)node.Member).GetValue(target);
                    break;
                default:
                    value = target = null;
                    break;
            }
            if (target != null) return Expression.Constant(value, node.Type);
        }
        return base.VisitMember(node);
    }
}

class Sample
{
    public int? Number{set;get;}
    public DateTimeOffset Date{set;get;}
}

【讨论】:

  • 感谢您的快速回答,甚至不知道 ExpressionVisitor 这样的东西甚至存在 :)
【解决方案2】:

如果您可以依赖Microsoft .NET Framework/CoreFX 的实现细节会在某个时间中断未来,看看下面剧透框中的内容:

这是Expression.DebugView property。你需要做一些事情,比如通过反射找到它。
它是implemented using an ExpressionVisitor,就像在Marc Gravell's answer to this question. 中所做的一样

我要再次强调这一点:这是私有财产。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-09-02
    • 2018-11-09
    • 2020-05-30
    • 2011-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-26
    相关资源
    最近更新 更多