AndAlso для двух параметров
Пытаюсь собрать Expression> из двух двух через AndAlso
internal static Expression<Func<Contact, PersonIdentity, bool>> Construct(ContactMatchOptions options)
{
Expression<Func<Contact, PersonIdentity, bool>> predicate =
(a, b) => StringDupe(a.Firstname, b.FirstName) &&
StringDupe(a.Lastname, b.LastName) &&
StringDupe(a.Middlename, b.MiddleName);
if (options == ContactMatchOptions.SimpleMatch)
return predicate;
if (options == ContactMatchOptions.WithEmail)
{
Expression<Func<Contact, PersonIdentity, bool>> exprWithEmail = (a, b) => WithEmail(a, b);
predicate.AndAlso(exprWithEmail);
}
return predicate;
}
Ранее я такое делал только для случая одной переменной:
public static Expression<Func<T, bool>> AndAlso<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
{
var param = expr1.Parameters[0];
if (ReferenceEquals(param, expr2.Parameters[0]))
{
return Expression.Lambda<Func<T, bool>>(Expression.AndAlso(expr1.Body, expr2.Body), param);
}
return Expression.Lambda<Func<T, bool>>(Expression.AndAlso(expr1.Body, Expression.Invoke(expr2, param)), param);
}
Наивная попытка обобщить:
public static Expression<Func<T1, T2, bool>> AndAlso<T1, T2>(this Expression<Func<T1, T2, bool>> expr1, Expression<Func<T1, T2, bool>> expr2)
{
var param = expr1.Parameters[0];
if (ReferenceEquals(param, expr2.Parameters[0]))
{
return Expression.Lambda<Func<T1, T2, bool>>(Expression.AndAlso(expr1.Body, expr2.Body), param);
}
return Expression.Lambda<Func<T1, T2, bool>>(Expression.AndAlso(expr1.Body, Expression.Invoke(expr2, param)), param);
}
компилируется но выдаёт исключение в рантайме:
System.InvalidOperationException : Неверное количество аргументов, заданных для лямбда-вызова
в System.Linq.Expressions.Expression.ValidateArgumentCount(MethodBase method, ExpressionType nodeKind, Int32 count, ParameterInfo[] pis)
в System.Linq.Expressions.Expression.ValidateArgumentTypes(MethodBase method, ExpressionType nodeKind, ReadOnlyCollection`1& arguments)
в System.Linq.Expressions.Expression.Invoke(Expression expression, IEnumerable`1 arguments)
в StandardSnippets.Extensions.QueryBuilder.AndAlsoExtension.AndAlso[T1,T2](Expression`1 expr1, Expression`1 expr2)
Какие параметры (expr1.Parameters[0] (Contact) и expr1.Parameters[1] (PersonIdentity)) и куда компилятор ожидает?
Мне нужно получить такое дерево выражений в итоге:
Постепенно начал дампить параметры и подбирать под нужную структуру, компилируется, но дерево выглядит иначе:
public static Expression<Func<T1, T2, bool>> AndAlso<T1, T2>(this Expression<Func<T1, T2, bool>> expr1, Expression<Func<T1, T2, bool>> expr2)
{
var param1 = expr1.Parameters[0];
//param1.Dump();
var param2 = expr1.Parameters[1];
//param2.Dump();
return Expression.Lambda<Func<T1, T2, bool>>(Expression.AndAlso(expr1.Body, expr2.Body), param1, param2);
}
Ответы (1 шт):
Автор решения: A K
→ Ссылка
Предыдущая версия ответа не работала, всё-таки надо было использовать замену переменных:
public static Expression<Func<T1, T2, bool>> AndAlso<T1, T2>(this Expression<Func<T1, T2, bool>> left, Expression<Func<T1, T2, bool>> right)
{
var replaced = right.Body
.ReplaceParameter(right.Parameters[0], left.Parameters[0])
.ReplaceParameter(right.Parameters[1], left.Parameters[1]);
var body = Expression.AndAlso(left.Body, replaced);
return Expression.Lambda<Func<T1, T2, bool>>(body, left.Parameters);
}
Использовал ParameterReplacer отсюда: https://stackoverflow.com/a/36651409/5752652
