这只是一个好奇的问题,我想知道是否有人有一个很好的答案:
在.NET Framework类库中,我们有两个方法:
public static IQueryableWhere ( this IQueryable source, Expression > predicate ) public static IEnumerable Where ( this IEnumerable source, Func predicate )
他们为什么用Func
而不是Predicate
?好像Predicate
只由List
和Array
,而Func
所使用的几乎所有Queryable
和Enumerable
方法和扩展方法...什么与怎么了?
虽然Predicate
已经同时推出了,List
并且Array
在.net 2.0中,不同的Func
和Action
变体来自.net 3.5.
因此,这些Func
谓词主要用于LINQ运算符的一致性.作为.NET 3.5,有关使用的Func
和Action
的方针状态:
使用新的LINQ类型
Func<>
而Expression<>
不是自定义委托和谓词
我以前想过这个.我喜欢这个Predicate
代表 - 这很好,很有描述性.但是,您需要考虑以下的重载Where
:
Where(IEnumerable , Func ) Where (IEnumerable , Func )
这允许您根据条目的索引进行过滤.那是好的和一致的,而:
Where(IEnumerable , Predicate ) Where (IEnumerable , Func )
不会.
当然,使用Func
而不是特定委托的实际原因是C#将单独声明的委托视为完全不同的类型.
即使Func
和Predicate
两者具有相同的参数和返回类型,它们不是赋值兼容.因此,如果每个库都为每个委托模式声明了自己的委托类型,那么除非用户插入"桥接"委托来执行转换,否则这些库将无法互操作.
// 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希望这将缓解不兼容的委托类型的问题.每个人的代表都会很好地一起玩,因为他们只会根据他们的参数/返回类型进行匹配.
它没有解决所有问题,因为Func
(和Action
)不能有out
或ref
参数,但那些不太常用.
更新: Svish在评论中说:
仍然,将参数类型从Func切换到Predicate并返回,似乎没有任何区别?至少它仍然没有任何问题编译.
是的,只要你的程序只为代理分配方法,就像我的Main
函数的第一行一样.编译器以静默方式为新的委托对象生成代码,该委托对象转发给该方法.所以在我的Main
函数中,我可以改变x1
为类型ExceptionHandler2
而不会导致问题.
但是,在第二行,我尝试将第一个委托分配给另一个委托.即使第二个委托类型具有完全相同的参数和返回类型,编译器也会给出错误CS0029: Cannot implicitly convert type 'ExceptionHandler1' to 'ExceptionHandler2'
.
也许这会让它更清晰:
public static bool IsNegative(int x) { return x < 0; } static void Main(string[] args) { Predicatep = IsNegative; Func f = IsNegative; p = f; // Not allowed }
我的方法IsNegative
是分配到一个非常好的东西p
和f
变数,只要我这样做直接.但后来我无法将其中一个变量分配给另一个变量.
建议(3.5及以上)是使用Action<...>
和Func<...>
- 为"为什么?" - 一个优点是" Predicate
"只有在你知道"谓词"意味着什么时才有意义 - 否则你需要查看对象浏览器(等)以找到signatute.
反过来Func
遵循标准模式; 我可以立即告诉我这是一个功能,需要一个T
并返回一个bool
- 不需要理解任何术语 - 只需应用我的真实测试.
对于"谓词",这可能没问题,但我很欣赏标准化的尝试.它还允许与该区域中的相关方法进行大量奇偶校验.