I am using my own extension methods of IQueryable<> to create chainable queries such as FindAll().FindInZip(12345).NameStartsWith(\"XYZ\").OrderByHowIWantIt() etc. which
In an ideal world I personally think || and && operators would be the most simple and readable. However it won't compile.
operator ' ||' cannot be applied to operands of type '
Expression' and '> Expression'>
Therefore I use an extension method for this. In your example it would look like this:
.Where(FindInZip(12345).Or(NameStartsWith("XYZ")).And(PostedOnOrAfter(DateTime.Now)).
Instead of:
.Where(FindInZip(12345) || NameStartsWith("XYZ") && (PostedOnOrAfter(DateTime.Now)).
Expression example:
private Expression> PostedOnOrAfter(DateTime cutoffDate)
{
return post => post.PostedOn >= cutoffDate;
};
Extension method:
public static class PredicateExtensions
{
///
/// Begin an expression chain
///
///
/// Default return value if the chanin is ended early
/// A lambda expression stub
public static Expression> Begin(bool value = false)
{
if (value)
return parameter => true; //value cannot be used in place of true/false
return parameter => false;
}
public static Expression> And(this Expression> left,
Expression> right)
{
return CombineLambdas(left, right, ExpressionType.AndAlso);
}
public static Expression> Or(this Expression> left, Expression> right)
{
return CombineLambdas(left, right, ExpressionType.OrElse);
}
#region private
private static Expression> CombineLambdas(this Expression> left,
Expression> right, ExpressionType expressionType)
{
//Remove expressions created with Begin()
if (IsExpressionBodyConstant(left))
return (right);
ParameterExpression p = left.Parameters[0];
SubstituteParameterVisitor visitor = new SubstituteParameterVisitor();
visitor.Sub[right.Parameters[0]] = p;
Expression body = Expression.MakeBinary(expressionType, left.Body, visitor.Visit(right.Body));
return Expression.Lambda>(body, p);
}
private static bool IsExpressionBodyConstant(Expression> left)
{
return left.Body.NodeType == ExpressionType.Constant;
}
internal class SubstituteParameterVisitor : ExpressionVisitor
{
public Dictionary Sub = new Dictionary();
protected override Expression VisitParameter(ParameterExpression node)
{
Expression newValue;
if (Sub.TryGetValue(node, out newValue))
{
return newValue;
}
return node;
}
}
#endregion
}
A really good article about LINQ Queries by Extending Expressions. Also the source of the extension method that I use.
https://www.red-gate.com/simple-talk/dotnet/net-framework/giving-clarity-to-linq-queries-by-extending-expressions/