将谓词<t>转换为Func <t,bool =“”> </t,> </t>

时间:2014-08-27 15:58:45

标签: c# linq

我有一个成员Predicate的类,我想在Linq表达式中使用它:

using System.Linq;

class MyClass
{

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

    private IEnumerable<Instrument> m_instrumentList;

    private Predicate<Instrument> m_filterExpression;
}

当我读到&#34; Predicate<T>完全等同于Func<T, bool>&#34; (see here),我希望这可行,因为All作为参数:Func<Instrument, bool> predicate

然而,我收到错误:

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

有没有办法将谓词转换为该函数将吞下的参数?

6 个答案:

答案 0 :(得分:13)

这两种类型代表相同的逻辑签名,但这并不意味着它们只是可互换的。例如,直接分配不会起作用 - 但您可以从Func<T, bool>创建新的Predicate<T, bool>。示例代码:

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

这有点像两个具有相同值的enum类型 - 您可以在它们之间进行转换,但您必须明确地进行转换。他们仍然是分开的类型。

在你的情况下,这意味着你可以写:

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

当然,其他答案所建议的lambda表达方法也会起作用。

答案 1 :(得分:10)

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

答案 2 :(得分:6)

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

答案 3 :(得分:3)

您可以通过调用Invoke将谓词转换为方法。所有代表都有这个成员。代表们没有结构身份,但方法可以转换为匹配的代表。此修复具有较小的性能成本,因为它添加了额外的间接层。但是,这个问题的大多数解决方案都有这个问题。 Eric Lippert在http://blog.coverity.com/2014/06/18/delegates-structural-identity更详细地讨论了这一点。

在您的具体情况下,将return m_instrumentList.All(m_filterExpression);替换为return m_instrumentList.All(m_filterExpression.Invoke);

演示实际问题的示例代码。

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;
}

答案 4 :(得分:1)

由于有很多答案,我将添加一个只是为了好玩。 如果您希望编译代码,可以使用扩展方法

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

    private IEnumerable<Instrument> m_instrumentList;

    private Predicate<Instrument> m_filterExpression;
}

在同一名称空间中添加此类

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

答案 5 :(得分:1)

正如Brian所说,您可以通过Invoke将谓词转换为方法:

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