How to convert Func<T, bool> to Predicate<T>?
Asked Answered
D

4

30

Yes I've seen this but I couldn't find the answer to my specific question.

Given a lambda testLambda that takes T and returns a boolean (I can make it either Predicate or Func that's up to me)

I need to be able to use both List.FindIndex(testLambda) (takes a Predicate) and List.Where(testLambda) (takes a Func).

Any ideas how to do both?

Disorganization answered 8/4, 2009 at 18:29 Comment(0)
L
64

Easy:

Func<string,bool> func = x => x.Length > 5;
Predicate<string> predicate = new Predicate<string>(func);

Basically you can create a new delegate instance with any compatible existing instance. This also supports variance (co- and contra-):

Action<object> actOnObject = x => Console.WriteLine(x);
Action<string> actOnString = new Action<string>(actOnObject);

Func<string> returnsString = () => "hi";
Func<object> returnsObject = new Func<object>(returnsString);

If you want to make it generic:

static Predicate<T> ConvertToPredicate<T>(Func<T, bool> func)
{
    return new Predicate<T>(func);
}
Loralyn answered 8/4, 2009 at 18:31 Comment(12)
They could at least have provided an overload for FindIndexDisorganization
What sort of "games"? What do you mean?Loralyn
Predicate<T> conceptually == Func<T, bool> but they're still not the same. Yes, Predicate<T> was a .Net 2.0 thing but now that its deprecated there should be one way to do the same thing.Disorganization
@George: There would be one way to do things if they could retire Predicate<T>. Unfortunately, some code was written using it, and retiring this type would break that code.Heroine
Exactly. Backward compatibility is a big issue.Loralyn
Sure, but they could provide some overloads for methods that use Predicate<T> or even better, add an implicit type conversion.Disorganization
@George: that'd be a lot of overloads everything obsoleted... as for implicit type conversions, have you looked at what that does to the complexity and usability of C++ (e.g. that bool and void* can be confused in resolving overloads)?Serafinaserafine
It would also break the use of lambda expressions for those methods, because they'd be equally valid for the two overloads.Loralyn
Is the Predicate<T> constructor documented somewhere? MSDN seems to only reference creating a Predicate<T> from a Lambda or a method, never with new.Barbados
@gilly3: There's no specific Predicate<T> constructor - it's just a delegate type, which can be constructed in the same ways as any other delegate.Loralyn
Ok, so this article on MSDN (barely) documents using new to create delegates. It shows updated syntax for later versions of .Net. But, Visual Studio tells me I can't use this updated syntax between two delegates (such as Func<T, bool> and Predicate<T>). Apparently, I must use new. Using new with delegate types is hardly documented at all on MSDN - I can't find an example of passing a delegate instance as the argument. Section 7.6.10.5 in the C# spec contains what I was looking for, but that is hardly satisfying.Barbados
@gilly3: Yup, it's not a very commonly used way of instantiating delegates. I don't even cover it in my delegates/events article (although I'm sure it's in C# in Depth somewhere :)Loralyn
D
10

I got this:

Func<object, bool> testLambda = x=>true;
int idx = myList.FindIndex(x => testLambda(x));

Works, but ick.

Disorganization answered 8/4, 2009 at 18:31 Comment(1)
Thanks, you save my dayHeinous
T
5

I'm a little late to the game, but I like extension methods:

public static class FuncHelper
{
    public static Predicate<T> ToPredicate<T>(this Func<T,bool> f)
    {
        return x => f(x);
    }
}

Then you can use it like:

List<int> list = new List<int> { 1, 3, 4, 5, 7, 9 };
Func<int, bool> isEvenFunc = x => x % 2 == 0;
var index = list.FindIndex(isEvenFunc.ToPredicate());

Hmm, I now see the FindIndex extension method. This is a little more general answer I guess. Not really much different from the ConvertToPredicate either.

Timi answered 7/7, 2011 at 15:48 Comment(0)
S
0

Sound like a case for

static class ListExtensions
{
  public static int FindIndex<T>(this List<T> list, Func<T, bool> f) {
    return list.FindIndex(x => f(x));
  }
}

// ...
Func<string, bool> f = x=>Something(x);
MyList.FindIndex(f);
// ...

I love C#3 ...

Samford answered 8/4, 2009 at 19:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.