Using C# 3.5 I wanted to build up a predicate to send to a where clause piece by piece. I have created a very simple Console Application to illustrate the solution that I arrived at. This works perfectly. Absolutely perfectly. But I have NO idea how or why.
public static Func<Tran, bool> GetPredicate()
{
Func<Tran, bool> predicate = null;
predicate += t => t.Response == "00";
predicate += t => t.Amount < 100;
return predicate;
}
When I say 'predicate +=', what does that mean? predicate -= appears to do nothing and ^=, &=, *=, /= aren't liked by the compiler.
The compiler doesn't like 'predicate = predicate + t => t.Response....' either.
What have I stumbled on? I know what it does, but how does it do it?
If anyone wants to go delve into more complicated lambda's, please do so.
If you want to combine predicates, try this;
You call it like this;
The += is syntactic sugar specifically implemented to support adding handlers to events. Since events are just a special case of delegate, and Func is also a delegate, the syntax appears to work here.
But are you sure it works as expected? By that I mean, do you expect an AND or OR evaluation? How would you implement the opposite if you wanted it? Are you sure it's not just returning the result of the first? Or the last?
"delegate += method" is operator for multicast delegate to combine method to delegate. In the other hand "delegate -= method" is operator to remove method from delegate. It is useful for Action.
In this case, only Method1 and Method3 will run, Method2 will not run because you remove the method before invoke the delegate.
If you use multicast delegate with Func, the result will be last method.
In this case, the result will be 3, since method "() => 3" is the last method added to delegate. Anyway all method will be called.
In your case, method "t => t.Amount < 100" will be effective.
If you want to combine predicate, I suggest these extension methods.
Usage
EDIT: correct the name of extension methods as Keith suggest.
Actually, that doesn't work. Try to test it with a case where the first condition FAILS but the second one passes. You'll find that it'll return true. The reason is, because when dealing with multicast delegates that return values, only the last value is returned. For example:
This will return TRUE because the last function call returns true (it's less than 20). In order to really make it work, you need to call:
which returns an array of delegates. You then need to make sure they ALL return true, for the final result to be true. Make sense?
Expanding on BFree's answer (+1'd it)
If you want to get the behavior you're looking for, you'll need to explicitly chain the predicates together. Here is an example
When you use += or -= when delegate types, that just gives a call to
Delegate.Combine
andDelegate.Remove
.The important thing about multicast delegates is that the return value of all but the last executed delegate is ignored. They all get executed (unless an exception is thrown), but only the last return value is used.
For predicates, you might want to do something like:
You'd then do:
EDIT: Here's a more general solution which is quite fun, if a bit bizarre...
So you could then implement And as:
(I personally prefer this over using
GetInvocationList()
, because you end up with a predicate you can pass to other bits of LINQ etc.)