Итак, во-первых, вам нужно удалить универсальный аргумент TResult
, потому что ваш код требует, чтобы было строкой.Просто замените все использования этого типа на string
, потому что любой другой тип не будет работать с этим методом.
Далее, вместо того, чтобы пытаться создать все выражение "вручную", гораздо лучшесоздать выражение, которое принимает строку и вычисляет логическое значение, используя соответствующую функцию сравнения, а затем просто объединить это выражение с предоставленным выражением.В общем, я бы сказал, что вы хотите избегать построения выражений вручную всякий раз, когда вы можете возможно избежать этого.Ваш код будет короче, проще для понимания и, что важно, , статически проверенный компилятором .
Поэтому мы начнем с адаптации вашего RightMethod
для возврата Expression
:
static Expression<Func<string, bool>> ComparisonExpression(bool start, bool end, string toCompare)
{
if (start && end)
return value => value.Contains(toCompare);
if (start)
return value => value.StartsWith(toCompare);
if (end)
return value => value.EndsWith(toCompare);
else
return value => value.Equals(toCompare);
}
Далее нам понадобится способ составления двух выражений вместе.Здесь мы должны построить его вручную, но его можно написать для составления любых двух произвольных выражений , так что нам не нужно переписывать код каждый раз, когда нужно объединить два выражения.
public static Expression<Func<TSource, TResult>> Compose<TSource, TIntermediate, TResult>(
this Expression<Func<TSource, TIntermediate>> first,
Expression<Func<TIntermediate, TResult>> second)
{
var param = Expression.Parameter(typeof(TSource));
var intermediateValue = first.Body.ReplaceParameter(first.Parameters[0], param);
var body = second.Body.ReplaceParameter(second.Parameters[0], intermediateValue);
return Expression.Lambda<Func<TSource, TResult>>(body, param);
}
, который использует следующий код для фактической замены параметров:
public static Expression ReplaceParameter(this Expression expression,
ParameterExpression toReplace,
Expression newExpression)
{
return new ParameterReplaceVisitor(toReplace, newExpression)
.Visit(expression);
}
public class ParameterReplaceVisitor : ExpressionVisitor
{
private ParameterExpression from;
private Expression to;
public ParameterReplaceVisitor(ParameterExpression from, Expression to)
{
this.from = from;
this.to = to;
}
protected override Expression VisitParameter(ParameterExpression node)
{
return node == from ? to : base.Visit(node);
}
}
И теперь ваш метод довольно тривиален, поскольку он почти ничего не делает, кроме вызова наших двух методов:
public static Expression<Func<T, bool>> AddStringCompareCriteria<T>(Expression<Func<T, string>> member, string toCompare)
{
toCompare = toCompare.Trim();
var start = toCompare[0] == '*';
var end = toCompare[toCompare.Length - 1] == '*';
toCompare = toCompare.Trim('*');
return member.Compose(ComparisonExpression(start, end, toCompare));
}