force Expression<> to evaluate local variables

2019-05-06 19:29发布

I have something like this in 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;}
}

it outputs

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

is there any possible way to keep the variables but have it output something like this:

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

2条回答
我欲成王,谁敢阻挡
2楼-- · 2019-05-06 19:49

If you are OK taking a dependency on an implementation detail of Microsoft's .NET Framework/the CoreFX that will break at some time in the future, take a look at what's in the spoiler box below:

There's the Expression.DebugView property. You'll need to do something like finding it via reflection.
It's implemented using an ExpressionVisitor, like what's done in Marc Gravell's answer to this question.

I'm going to emphasize this again: this is a private property.

查看更多
相关推荐>>
3楼-- · 2019-05-06 19:54

Here we go; output first:

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

This will never output Parse(...), because your expression does not contain a parse: you have already evaluated that by the time you put it into a lambda.

Note also that this handles one level of captured variable. For more complex (nested) capture contexts, you'll have to recursively fetch the values from the capture classes:

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;}
}
查看更多
登录 后发表回答