【问题标题】:Expression to check if a property is equal to a constant检查属性是否等于常量的表达式
【发布时间】:2015-02-16 06:45:42
【问题描述】:

我正在尝试组合两个工作表达式。

  • left:返回属性值的表达式

    Expression<Func<TimeSlot, Guid>> left = x => x.TimeSlotId;
    
  • 右:返回常量值的表达式(变量guid的值)

    Expression<Func<TimeSlot, Guid>> right = Expression.Lambda<Func<TimeSlot, Guid>>
                        (Expression.Constant(guid, typeof(Guid)), input);
    

现在我想将这两个表达式打包成另一个表达式,使这两个结果相等。这有效:

    // given a TimeSlot slot which guid is equal to the constent
    bool eq1 = left.Compile()(slot) == right.Compile()(slot); // true

但这不起作用 ParameterExpression input = Expression.Parameter(typeof(TimeSlot));

        Expression<Func<TimeSlot, bool>> expression = Expression.Lambda<Func<TimeSlot, bool>>
            (Expression.Equal(left, right), input);

        bool eq2 = expression.Compile()(slot); // false

我完全困惑为什么这个结果是不同的。特别是因为这个表达式的 DebugView 看起来像这样:

{Param_0 => (x => x.TimeSlotId == Param_0 => 351155b2-20a5-4c48-8722-ddf0e1f9055a)}

=

.Lambda #Lambda1<System.Func`2[SilverFit.Database.Model.TimeSlot,System.Boolean]>(SilverFit.Database.Model.TimeSlot $var1)
{
    .Lambda #Lambda2<System.Func`2[SilverFit.Database.Model.TimeSlot,System.Guid]> == .Lambda #Lambda3<System.Func`2[SilverFit.Database.Model.TimeSlot,System.Guid]>
}

.Lambda #Lambda2<System.Func`2[SilverFit.Database.Model.TimeSlot,System.Guid]>(SilverFit.Database.Model.TimeSlot $x) {
    $x.TimeSlotId
}

.Lambda #Lambda3<System.Func`2[SilverFit.Database.Model.TimeSlot,System.Guid]>(SilverFit.Database.Model.TimeSlot $var1) {
    .Constant<System.Guid>(351155b2-20a5-4c48-8722-ddf0e1f9055a)
}

有谁知道创建比较表达式结果和常量的表达式的正确方法?

【问题讨论】:

    标签: c# lambda expression


    【解决方案1】:

    您看到的调试输出准确地告诉您发生了什么,以及为什么它不工作。特别是,您与等式表达式比较的不是表达式返回的值,而是表达式本身。

    一个重要线索是两个表达式都需要输入,但即使在调试输出中,您也可以看到该输入仅用于相等比较的一侧,并且仅作为第二个表达式的输入参数。

    恕我直言,分别编译这两个表达式实际上并不是一个糟糕的解决方案。你甚至可以缓存编译结果:

    Func<TimeSlot, Guid> d1 = left.Compile(), d2 = right.Compile();
    Func<TimeSlot, bool> d2 = x => d1(x) == d2(x);
    

    但是如果你真的想将操作组合成一个表达式,那么你可以这样做:

    ParameterExpression param1 = Expression.Parameter(typeof(TimeSlot));
    Expression<Func<TimeSlot, bool>> expression = Expression.Lambda<Func<TimeSlot, bool>>(
        Expression.Equal(
            Expression.Invoke(left, param1),
            Expression.Invoke(right, param1)),
        param1);
    

    这是一个演示该技术的完整代码示例:

    class Program
    {
        class A
        {
            public Guid Guid { get; private set; }
    
            public A()
            {
                Guid = Guid.NewGuid();
            }
        }
    
        static void Main(string[] args)
        {
            // Set up data values
            A a = new A();
            Guid guid = a.Guid;
    
            // Create expressions to be composed
            Expression<Func<A, Guid>> e1 = arg => arg.Guid, e2 = arg => guid;
    
            // Create lambda expression: invoke both expressions, compare the result
            ParameterExpression param1 = Expression.Parameter(typeof(A));
            Expression<Func<A, bool>> e3 = Expression.Lambda<Func<A, bool>>(
                Expression.Equal(
                    Expression.Invoke(e1, param1),
                    Expression.Invoke(e2, param1)),
                param1);
    
            // Compile to an actual delegate instance
            Func<A, bool> d1 = e3.Compile();
    
            // Check the result
            Console.WriteLine(d1(a));
        }
    }
    

    【讨论】:

    • 谢谢,Expression.Invoke 可以解决问题。我在调试输出中没有注意到它正在比较表达式。我认为== 的优先级低于=&gt;。这让我觉得在比较结果之前对这两个表达式都进行了评估。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-09
    • 2017-08-20
    • 1970-01-01
    相关资源
    最近更新 更多