28

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?

Community
  • 1
  • 1
George Mauer
  • 117,483
  • 131
  • 382
  • 612

4 Answers4

61

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);
}
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • They could at least have provided an overload for FindIndex – George Mauer Apr 08 '09 at 18:37
  • What sort of "games"? What do you mean? – Jon Skeet Apr 08 '09 at 18:38
  • Predicate conceptually == Func but they're still not the same. Yes, Predicate was a .Net 2.0 thing but now that its deprecated there should be one way to do the same thing. – George Mauer Apr 08 '09 at 18:45
  • @George: There would be one way to do things if they could retire Predicate. Unfortunately, some code was written using it, and retiring this type would break that code. – Amy B Apr 08 '09 at 18:49
  • 2
    Exactly. Backward compatibility is a *big* issue. – Jon Skeet Apr 08 '09 at 18:50
  • Sure, but they could provide some overloads for methods that use Predicate or even better, add an implicit type conversion. – George Mauer Apr 08 '09 at 18:55
  • @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)? – Pontus Gagge Apr 08 '09 at 19:20
  • It would also break the use of lambda expressions for those methods, because they'd be equally valid for the two overloads. – Jon Skeet Apr 08 '09 at 19:25
  • Is the `Predicate` constructor documented somewhere? [MSDN](https://msdn.microsoft.com/en-us/library/bfcke1bz(v=vs.110).aspx) seems to only reference creating a `Predicate` from a Lambda or a method, never with `new`. – gilly3 Sep 22 '15 at 17:50
  • @gilly3: There's no specific `Predicate` constructor - it's just a delegate type, which can be constructed in the same ways as any other delegate. – Jon Skeet Sep 22 '15 at 17:51
  • Ok, so [this article on MSDN](https://msdn.microsoft.com/en-us/library/ms173176.aspx) (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` and `Predicate`). 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. – gilly3 Sep 22 '15 at 18:48
  • @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 :) – Jon Skeet Sep 22 '15 at 18:58
10

I got this:

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

Works, but ick.

George Mauer
  • 117,483
  • 131
  • 382
  • 612
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.

Michael Welch
  • 1,754
  • 2
  • 19
  • 32
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 ...

MartinStettner
  • 28,719
  • 15
  • 79
  • 106