Reputation: 3966
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
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
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
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
Reputation: 17837
return m_instrumentList.All(i => m_filterExpression(i));
Upvotes: 7
Reputation: 7618
public bool DoAllHaveSomeProperty()
{
return m_instrumentList.All(i => m_filterExpression(i));
}
Upvotes: 16
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