Why Func<T,Bool> Instead of Predicate<T>

Why FuncT,bool instead of PredicateT?

While Predicate has been introduced at the same time that List<T> and Array<T>, in .net 2.0, the different Func and Action variants come from .net 3.5.

So those Func predicates are used mainly for consistency in the LINQ operators. As of .net 3.5, about using Func<T> and Action<T> the guideline states:

Do use the new LINQ types Func<> and
Expression<> instead of custom
delegates and predicates

Why a `PredicateT` doesn't match a `FuncT,bool`?

C# specification is clear about that:

15.1 Delegate declarations

Delegate types in C# are name equivalent, not structurally equivalent.
Specifically, two different delegate types that have the same
parameter lists and return type are considered different delegate
types
.

That's why your code doesn't compile.

You can make it work by calling the delegate, instead of passing it:

public static T FirstEffective (IEnumerable<T> list) {
Predicate<T> pred = x => x != null;
return Enumerable.FirstOrDefault (list, x => pred(x));
}

Update

There is a great blog post by Eric Lippert: former member of C# Team as Microsoft, which answers your question in much details: Delegates and structural identity.

Why is it impossible to cast FuncT, bool to PredicateT?

It is a little silly that the IEnumerable<T>.Where extension method and List<T>'s RemoveAll method take two different types. However, this is a simple work-around, since the local function can be used to initialize both a Func<int, bool> and a Predicate<int>:

var l = new List<int> {1, 2, 3, 5, 5, 6, 6};
bool Pred(int i) => i < 5;
var wh = l.Where(Pred);
var rem = l.RemoveAll(Pred);

Isn't FuncT, bool and PredicateT the same thing after compilation?

They share the same signature, but they're still different types.

Using PredicateT or a FuncT in method to filter

You can use

public IEnumerable<Claim> FindAllClaims(this IEnumerable<Claim> source, Expression<Predicate<Claim>> condition) {
return source.Where(condition)
}

or

public IEnumerable<Claim> FindAllClaims(this IEnumerable<Claim> source, Expression<Func<Claim,bool>> condition) {
return source.Where(condition)
}

Converting a PredicateT to a FuncT, bool

public bool DoAllHaveSomeProperty()
{
return m_instrumentList.All(i => m_filterExpression(i));
}

FindAll - PredicateTSource vs FuncTSource, bool

They have the same signature, but they are fundamentally different types and cannot be cast as a reference-preserving conversion. Since FindAll wants a Predicate<T>: use Predicate<T>.

Would it be nice if they were castable like this? Maybe, but it would require CLR and language changes, and is unlikely to happen.



Related Topics



Leave a reply



Submit