A simple fluent api to combine predicates as needed
I've found it necessary several times to author predicates in numerous ways, and it always ends up being extremely difficult to read, write, and work around.
A simple tree-based predicate combinator which uses a basic fluent api
Currently, the api only allows for simple fluent creation of either a
Predicate<T>
or a Func<T,bool>
using and/or statements, as well as
grouped statements.
A PredicateBuilder<T>
is used to create the predicate. Usage is simple:
// if (s.Contains('a'))
var builder = new PredicateBuilder<string>();
builder.Build()
.WithPredicate(s => s.Contains('a'))
.AsFunc();
Of course, more complex predicates can be built:
// if (s.Contains('a') || string.Equals('b'))
builder.Build()
.WithPredicate(s => s.Contains('a'))
.Or(s => string.Equals('b')
.AsFunc();
Predicates can include groups. These groups are themselves predicate trees which is ultimately added to the main expression tree. See Combinator Logic.
A group requires an Action<IFluentPredicateBuilder<T>>
to create the group's expression
tree. Again, usage is relatively straightforward, just recursive.
// if ((s.Contains('a') && s.Contains('b')) ||
builder.Build()
.WithGroup(b =>
b.WithPredicate(s => s.Contains('a'))
.And(s => s.Contains('b')))
.Or(s => s == "Other Test");
Predicates are combined in groups. Groups can either be of And
or Or
combinators.
The first group is always an And
group. Whenever a statement is added, if the statements
combinator type is the same as the previous statement's, the statement is simply added to the
current tree. e.g. if a group is already an And
group, and another And
statement is added:
builder.Build().WithPredicate(A).And(B).And(C)
results in the equivalent statement A && B && C
. Wherever the combinator is switched, a new
tree is created with the current tree as the first child node of the new node.
builder.Build()
.WithPredicate(A)
.And(B)
.Or(C)
.OR(D)
.And(E)
Results in ((A && B) || C || D) && E