force Expression<> to evaluate local variables

本秂侑毒 提交于 2020-01-02 05:33:11

问题


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)))


回答1:


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;}
}



回答2:


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.



来源:https://stackoverflow.com/questions/12734464/force-expression-to-evaluate-local-variables

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!