【问题标题】:Expression.Lambda with multiple input selectors具有多个输入选择器的 Expression.Lambda
【发布时间】:2015-01-20 17:11:01
【问题描述】:

我正在尝试创建自己的自定义操作,我可以在数据库中使用它来查找受值更改影响的行。

我在此处查看操作员示例之间的 Jon Skeets:LINQ Between Operator 但我遇到了麻烦,因为我的操作包含多个参数输入

    public static IQueryable<TSource> LeavingRange<TSource, TKey>(this IQueryable<TSource> source,
        Expression<Func<TSource, TKey>> lowKeySelector,
        Expression<Func<TSource, TKey>> highKeySelector,
        Nullable<TKey> oldValue,
        Nullable<TKey> newValue)
            where TKey : struct, IComparable<TKey>
    

如您所见,我有 2 个选择器,但我不太确定如何将它们正确组合到我的 Expression.Lambda 调用的参数中。我尝试将两个输入表达式中的参数作为参数放入 lambda,但我认为我错过了一些东西。

Expression.Lambda<Func<TSource, bool>>(isLeavingRange, lowKeySelector.Parameters[0], highKeySelector.Parameters[0]);

这样做会产生以下错误:

为 lambda 声明提供的参数数量不正确

在构造 Lambda 时,组合输入参数的正确方法是什么?


支持信息

我的完整代码如下,但我认为相关位是两个选择器和Expression.Lambda 调用

    public static IQueryable<TSource> LeavingRange<TSource, TKey>(this IQueryable<TSource> source,
        Expression<Func<TSource, TKey>> lowKeySelector,
        Expression<Func<TSource, TKey>> highKeySelector,
        Nullable<TKey> oldValue,
        Nullable<TKey> newValue)
            where TKey : struct, IComparable<TKey>
    {
        Expression lowKey = Expression.Invoke(lowKeySelector, lowKeySelector.Parameters.ToArray());
        Expression highKey = Expression.Invoke(highKeySelector, highKeySelector.Parameters.ToArray());

        //is oldValue null which means it cant possibly be leaving
        var oldValueIsNotNull = Expression.NotEqual(Expression.Constant(oldValue, typeof(Nullable<TKey>)), Expression.Constant(null, typeof(Nullable<TKey>)));
        var newValueIsNull = Expression.Equal(Expression.Constant(newValue, typeof(Nullable<TKey>)), Expression.Constant(null, typeof(Nullable<TKey>)));
        var newValueIsNotNull = Expression.Not(newValueIsNull);

        var oldValueIsBetweenRange = Between(Expression.Convert(Expression.Constant(oldValue), typeof(TKey)), lowKey, highKey);
        var newValueIsNotBetweenRange = Expression.Not(Between(Expression.Convert(Expression.Constant(newValue), typeof(TKey)), lowKey, highKey));

        //IE leaving because its going from in the range to null
        var newValueIsNullAndOldValueIsBetweenRange = Expression.AndAlso(newValueIsNull, oldValueIsBetweenRange);

        var oldValueIsInRangeAndNewValueIsNot = Expression.AndAlso(newValueIsNotNull, Expression.AndAlso(oldValueIsBetweenRange, newValueIsNotBetweenRange));
        var isLeavingRange = Expression.AndAlso(oldValueIsNotNull, Expression.Or(newValueIsNullAndOldValueIsBetweenRange, oldValueIsInRangeAndNewValueIsNot));

        var leavingRange = Expression.Lambda<Func<TSource, bool>>(isLeavingRange, lowKeySelector.Parameters[0], highKeySelector.Parameters[0]);
        
        return source.Where(leavingRange);
    }

【问题讨论】:

  • 我相信回答者 Ripple 已经解决了您的问题。对我来说,这似乎是一个合适的答案。但如果不是,我会注意到您没有发布good, complete code example,没有它很容易误解上下文或问题,或者至少很难提供足够清晰和具体的答案以满足您的需求.

标签: c# linq lambda


【解决方案1】:

传递给Where() 的委托仅将集合中的每个元素作为参数, 所以你需要让调用lowKeySelectorhighKeySelector的两个表达式将相同的元素(ParameterExpression的相同实例)作为参数 并且还需要构建 lambda 表达式以将其用作参数。

public static IQueryable<TSource> LeavingRange<TSource, TKey>(this IQueryable<TSource> source,
     Expression<Func<TSource, TKey>> lowKeySelector,
     Expression<Func<TSource, TKey>> highKeySelector,
     Nullable<TKey> oldValue,
     Nullable<TKey> newValue)
         where TKey : struct, IComparable<TKey>
{
    ParameterExpression paramOfWhereDelg = Expression.Parameter(typeof(TSource), "p");

    Expression lowKey = Expression.Invoke(lowKeySelector, paramOfWhereDelg);
    Expression highKey = Expression.Invoke(highKeySelector, paramOfWhereDelg);

    // Build your expression tree
    //  ...

    var leavingRange = Expression.Lambda<Func<TSource, bool>>(isLeavingRange, paramOfWhereDelg);

    return source.Where(leavingRange);
}

(或者你可以用lowKeySelector.Parameters代替paramOfWhereDelg, 但我相信创建另一个 ParameterExpression 会更容易理解。)

【讨论】:

  • 效果很好,我不明白那个参数在做什么,看起来它只是 lambda 的输入。谢谢
猜你喜欢
  • 1970-01-01
  • 2014-09-04
  • 2022-07-13
  • 1970-01-01
  • 2019-05-08
  • 1970-01-01
  • 1970-01-01
  • 2013-05-06
  • 1970-01-01
相关资源
最近更新 更多