Predicate Composition
Builds a new predicate from existing ones, so that Where, Any, All and friends can be given a composed
condition without a lambda that restates it.
Func<T, bool> All<T>(params Func<T, bool>[] predicates)
Func<T, bool> Any<T>(params Func<T, bool>[] predicates)
Func<T, bool> Not<T>(Func<T, bool> predicate)
All is true when every predicate is true, Any when at least one is, Not inverts. They short-circuit like
&& and ||, and the predicates are evaluated left to right. All() with no predicates is always true and
Any() with none always false, following the LINQ methods of the same names.
The point is reuse. Predicates that have names can be combined by name, where a lambda would have to spell out each one again:
Func<User, bool> isActive = u => u.IsActive;
Func<User, bool> isAdmin = u => u.Role == Role.Admin;
Func<User, bool> isVerified = u => u.EmailVerified;
var activeAdmins = users.Where(All(isActive, isAdmin));
var needsAttention = users.Where(Any(Not(isVerified), Not(isActive)));
// Compared to
var activeAdmins = users.Where(u => isActive(u) && isAdmin(u));
Because the result is an ordinary Func<T, bool>, it composes further: Not(All(a, b)) is "not both".
True and False
True and False are predicates that ignore their arguments and return a constant, with overloads for zero
to four parameters:
bool True()
bool True<T1>(T1 ω1)
bool True<T1, T2>(T1 ω1, T2 ω2)
// … and the same for False
They are the predicate equivalents of Identity and NoOperation:
the thing to pass when an API demands a predicate and you have no condition. SingleOrNone() is implemented
as SingleOrNone(True).
// A feature flag that is always on in tests
Func<Request, bool> filter = isTestEnvironment ? True : IsAllowed;
// A default for an optional predicate parameter
IEnumerable<T> Filter<T>(IEnumerable<T> items, Func<T, bool>? predicate = null)
=> items.Where(predicate ?? True);