为什么Func <T,bool>而不是Predicate <T>?

这只是一个好奇的问题,我想知道如果有人有一个很好的答案:

在.NET Framework类库中,我们有例如这两个方法:

public static IQueryable<TSource> Where<TSource>( this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate ) public static IEnumerable<TSource> Where<TSource>( this IEnumerable<TSource> source, Func<TSource, bool> predicate ) 

为什么他们使用Func<TSource, bool>而不是Predicate<TSource> ? 似乎Predicate<TSource>仅被List<T>Array<T> ,而Func<TSource, bool>几乎被所有的QueryableEnumerable方法和扩展方法使用…这是怎么回事?

虽然Predicate已经在.net 2.0中同时引入了List<T>Array<T> ,但是不同的FuncAction变体来自.net 3.5。

所以那些Func谓词主要用于LINQ操作符的一致性。 从.net 3.5开始,关于使用Func<T>Action<T>的指导原则是 :

请使用新的LINQtypesFunc<>Expression<>来代替自定义委托和谓词

我以前想过这个。 我喜欢Predicate<T>委托 – 这是很好的和描述性的。 但是,您需要考虑Where的重载:

 Where<T>(IEnumerable<T>, Func<T, bool>) Where<T>(IEnumerable<T>, Func<T, int, bool>) 

这允许你基于条目的索引进行过滤。 这很好,一致,而:

 Where<T>(IEnumerable<T>, Predicate<T>) Where<T>(IEnumerable<T>, Func<T, int, bool>) 

不会的。

当然,使用Func而不是特定委托的真正原因是C#将单独声明的委托视为完全不同的types。

即使Func<int, bool>Predicate<int>都具有相同的参数和返回types,但它们不是分配兼容的。 因此,如果每个库都为每个委托模式声明自己的委托types,那么除非用户插入“桥接”委托来执行转换,否则这些库将不能互操作。

  // declare two delegate types, completely identical but different names: public delegate void ExceptionHandler1(Exception x); public delegate void ExceptionHandler2(Exception x); // a method that is compatible with either of them: public static void MyExceptionHandler(Exception x) { Console.WriteLine(x.Message); } static void Main(string[] args) { // can assign any method having the right pattern ExceptionHandler1 x1 = MyExceptionHandler; // and yet cannot assign a delegate with identical declaration! ExceptionHandler2 x2 = x1; // error at compile time } 

通过鼓励大家使用Func,Microsoft希望这可以缓解不兼容的委托types问题。 每个人的代表都会一起玩,因为他们只是根据参数/返回types进行匹配。

它并不能解决所有的问题,因为Func (和Action )不能有out参数,但是那些不常用的参数。

更新:在评论Svish说:

不过,从Func切换到Predicate并返回参数types似乎没有什么区别? 至less它仍然编译没有任何问题。

是的,只要你的程序只给委托分配方法,就像我的Main函数的第一行一样。 编译器以静默方式生成代码给新的委托对象,并转发给方法。 所以在我的Main函数中,我可以将x1更改为ExceptionHandler2types而不会导致问题。

但是,在第二行我尝试将第一个代理分配给另一个代理。 即使认为第二个委托types具有完全相同的参数和返回types,编译器给出错误CS0029: Cannot implicitly convert type 'ExceptionHandler1' to 'ExceptionHandler2'

也许这会更清楚:

 public static bool IsNegative(int x) { return x < 0; } static void Main(string[] args) { Predicate<int> p = IsNegative; Func<int, bool> f = IsNegative; p = f; // Not allowed } 

我的方法IsNegative是一个非常好的事情分配给pfvariables,只要我直接这样做。 但是我不能把这些variables中的一个指定给另一个。

build议(在3.5及以上版本)是使用Action<...>Func<...> – 为什么? – 一个好处是“ Predicate<T> ”只有在你知道“谓词”是什么意思的时候才有意义 – 否则你需要看对象浏览器(等)来find签名。

相反, Func<T,bool>遵循标准模式; 我可以立刻知道这是一个函数,需要一个T并返回一个bool – 不需要了解任何术语 – 只要应用我的真相testing。

对于“谓词”来说,这可能是确定的,但是我很欣赏标准化的尝试。 这也使得该领域的相关方法有了很大的平衡。