After reading post about List Predicates at the very informative BCL Team Blog, I did some research to see how flexible the predicates actually are.
I found out that none of the methods taking a Predicate as a parameter support chained delegates (more info about combining delegates), only the delegate added last to the chain is executed in my experience.
Example:
// Prepare collection
List<int> list = new List<int>( new int[]{1,2,3,4,5,6} );
// function to determine if the int is less than 5
Predicate<int> LT5 = delegate(int x){ return x < 5; };
// function to determine if the int is greater than 2
Predicate<int> GT2 = delegate(int x){ return x > 2; };
// combine the predicates:
// return true for 2 < x < 5
Predicate<int> GT2LT5 = null;
GT2LT5 += GT2;
GT2LT5 += LT5;
List<int> result = list.FindAll(GT2LT5);
// writes 1,2,3,4
result.ForEach( delegate( int x) { Console.WriteLine( x ); });
A work around would be to use the second delegate on the result collection after calling the FindAll method with the first delegate, but this doesn't scale with more delegates.
// first use the first delegate
List<int> intermediate = list.FindAll(LT5);
// now use the second delegate on the intermediate result
List<int> result = intermediate.FindAll(GT2);
// writes 3,4
result.ForEach( delegate( int x) {
Console.WriteLine( x );
});
Another solution is to enumerate through the collection and call each delegate in the invocation list.
// Prepare collection
List<int> list = new List<int>( new int[]{1,2,3,4,5,6} );
// function to determine if the int is less than 5
Predicate<int> LT5 = delegate(int x){
return x < 5;
};
// function to determine if the int is greater than 2
Predicate<int> GT2 = delegate(int x){
return x > 2;
};
// combine the predicates:
// return true for 2 < x < 5
Predicate<int> GT2LT5 = null;
GT2LT5 += GT2;
GT2LT5 += LT5;
// prepare result
List<int> result = new List<int>();
foreach(int i in list ){
bool valid = true;
// GetInvocationList returns all combined delegates
foreach( Predicate<int> match in GT2LT5.GetInvocationList() ){
valid = valid & match(i);
}
if( valid ){
result.Add(i);
}
}
// writes 3,4
result.ForEach( delegate( int x) {
Console.WriteLine( x );
});
Both solutions are less than ideal.