Expression.Lambda 具有多个输入选择器
Expression.Lambda with multiple input selectors
我正在尝试创建我自己的自定义操作,我可以在数据库中使用它来查找受值更改影响的行。
我正在查看运算符示例之间的 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]);
这样做会出现以下错误:
Incorrect number of parameters supplied for lambda declaration
构造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);
}
传递给 Where()
的委托只将集合中的每个元素作为参数,
所以你需要使调用 lowKeySelector
和 highKeySelector
的两个表达式采用相同的元素(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
会更容易理解。)
我正在尝试创建我自己的自定义操作,我可以在数据库中使用它来查找受值更改影响的行。
我正在查看运算符示例之间的 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]);
这样做会出现以下错误:
Incorrect number of parameters supplied for lambda declaration
构造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);
}
传递给 Where()
的委托只将集合中的每个元素作为参数,
所以你需要使调用 lowKeySelector
和 highKeySelector
的两个表达式采用相同的元素(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
会更容易理解。)