将Predicate转换为Func

24 浏览
0 Comments

将Predicate转换为Func

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

using System.Linq;
class MyClass
{
    public bool DoAllHaveSomeProperty()
    {
        return m_instrumentList.All(m_filterExpression);
    }
    private IEnumerable m_instrumentList;
    private Predicate m_filterExpression;
}

正如我在这里所读到的"Predicate是[...]与Func完全等效的",所以我期望这个可以工作,因为All接受的参数是:Func predicate

然而,我得到了错误:

Argument 2: cannot convert from 'System.Predicate' to 'System.Type'

有没有办法将这个谓词转换为该函数可以接受的参数?

0
0 Comments

将Predicate转换为Func的原因是在使用LINQ的All方法时,需要传入一个返回bool值的委托。而原始代码中的m_filterExpression是一个类型为Predicate的委托,因此需要将其转换为类型为Func的委托。

解决方法是通过将m_filterExpression委托转换为Func委托来实现。这可以通过在调用m_filterExpression委托时添加一个lambda表达式来完成:

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

这样做的原因是Predicate委托只接受一个参数并返回一个bool值,而Func委托接受一个参数并返回一个bool值。因此,通过在lambda表达式中将m_filterExpression作为参数传递给m_instrumentList.All方法,可以将其转换为Func委托。

需要注意的是,这种转换可能会带来一些额外的开销。作者在代码中提到了这一点,并表示已经对其进行了测量,发现它不会被编译或JIT优化掉。因此,使用此转换可能会对性能产生一些影响,需要注意。

0
0 Comments

问题的出现原因是Predicate和Func虽然具有相同的逻辑签名,但并不意味着它们可以直接互换使用。例如,直接赋值是不起作用的,但是可以通过Predicate创建一个新的Func。解决方法是使用new Func(predicate)来创建一个新的Func

在代码中,可以使用以下方式进行转换:

Predicate pred = x => x.Length > 10;
// Func func = pred; // 错误
Func func = new Func(pred); // 正确

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

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

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

当然,其他答案中提到的lambda表达式方法也可以正常工作。

使用new Func(predicate)比使用x => predicate(x)要简洁得多!谢谢!

0
0 Comments

将Predicate转换为Func是因为委托之间的结构身份不同。尽管委托没有结构身份,但是方法可以转换为匹配的委托。在解决这个问题时,有一个小的性能代价,因为它增加了一个额外的间接层。然而,大多数解决这个问题的方法都存在这个问题。在Eric Lippert的博客文章中提到了这个问题的更多细节。

在具体的案例中,可以通过调用Invoke来将谓词转换为方法。所有委托都有这个成员。以下是具体的代码示例:

void Main()
{
    Predicate t1 = Foo;
    Func t2 = Foo;
    Predicate t3 = t2.Invoke; //合法
    Func t4 = t1.Invoke; //合法
    Predicate t5 = t2; //不合法
    Func t6 = t1; //不合法
}
bool Foo(int x)
{
    return x > 20;
}

在解决这个问题时,只需要将`return m_instrumentList.All(m_filterExpression);`替换为`return m_instrumentList.All(m_filterExpression.Invoke);`即可。这样就将谓词转换为了方法。

0