Yellow
Yellow

Reputation: 3966

Converting a Predicate<T> to a Func<T, bool>

I have a class with a member Predicate which I would like to use in a Linq expression:

using System.Linq;

class MyClass
{

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

    private IEnumerable<Instrument> m_instrumentList;

    private Predicate<Instrument> m_filterExpression;
}

As I read that "Predicate<T> is [...] completely equivalent to Func<T, bool>" (see here), I would expect this to work, since All takes in as argument: Func<Instrument, bool> predicate.

However, I get the error:

Argument 2: cannot convert from 'System.Predicate<MyNamespace.Instrument>' to 'System.Type'

Is there a way to convert the predicate to an argument that this function will swallow?

Upvotes: 31

Views: 8059

Answers (6)

Arthur Khazbulatov
Arthur Khazbulatov

Reputation: 930

As Brian said, you can convert a predicate to a method via Invoke:

public bool DoAllHaveSomeProperty()
{
    return m_instrumentList.All(m_filterExpression.Invoke);
}

Upvotes: 1

Brian
Brian

Reputation: 25834

You can convert a predicate to a method by calling Invoke. All delegates have this member. Delegates don't have structural identity, but methods can be converted to matching delegates. This fix has a minor performance cost, as it adds an extra layer of indirection. However, most solutions to this problem have that problem. Eric Lippert discusses this in more detail at https://web.archive.org/web/20140625132124/http://blog.coverity.com/2014/06/18/delegates-structural-identity/ .

In your specific case, replace return m_instrumentList.All(m_filterExpression); with return m_instrumentList.All(m_filterExpression.Invoke);

Sample code demonstrating the actual problem.

void Main()
{
    Predicate<int> t1 = Foo;
    Func<int,bool> t2 = Foo;
    Predicate<int> t3 = t2.Invoke; //Legal
    Func<int,bool> t4 = t1.Invoke; //Legal
    Predicate<int> t5 = t2; //Illegal
    Func<int,bool> t6 = t1; //Illegal
}

bool Foo(int x)
{
    return x > 20;
}

Upvotes: 14

George Vovos
George Vovos

Reputation: 7618

Since there are a lot of answers i will add one more just for fun. If you want your code to compile you can use extention methods

//Original Code
class MyClass4
{
    public bool DoAllHaveSomeProperty()
    {
        return m_instrumentList.All(m_filterExpression);
    }

    private IEnumerable<Instrument> m_instrumentList;

    private Predicate<Instrument> m_filterExpression;
}

Add this class in the same namespace

public static class MyExtentions
{
    public static bool All(this IEnumerable<Instrument> enumer, Predicate<Instrument> pred)
    {
        return enumer.All(e => pred(e));
    }
}

Upvotes: 1

Julien Roncaglia
Julien Roncaglia

Reputation: 17837

return m_instrumentList.All(i => m_filterExpression(i));

Upvotes: 7

George Vovos
George Vovos

Reputation: 7618

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

Upvotes: 16

Jon Skeet
Jon Skeet

Reputation: 1503310

The two types represent the same logical signature, but that doesn't mean they're just interchangable. A straight assignment won't work, for example - but you can create a new Func<T, bool> from the Predicate<T, bool>. Sample code:

Predicate<string> pred = x => x.Length > 10;
// Func<string, bool> func = pred; // Error
Func<string, bool> func = new Func<string, bool>(pred); // Okay

This is a bit like having two enum types with the same values - you can convert between them, but you have to do so explicitly. They're still separate types.

In your case, this means you could write:

public bool DoAllHaveSomeProperty()
{
    return m_instrumentList.All(new Func<T, bool>(m_filterExpression));
}

The lambda expression approach suggested by other answers will work too, of course.

Upvotes: 27

Related Questions