为什么 Func而不是谓词?
这只是一个好奇问题,我想知道是否有人有一个好的答案:
在 .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
代替谓词
? 似乎 Predicate
仅由 List
和 Array
使用,而 Func
几乎被所有 Queryable
和 Enumerable
方法和扩展方法使用......这是怎么回事?
This is just a curiosity question I was wondering if anyone had a good answer to:
In the .NET Framework Class Library we have for example these two methods:
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
)
Why do they use Func<TSource, bool>
instead of Predicate<TSource>
? Seems like the Predicate<TSource>
is only used by List<T>
and Array<T>
, while Func<TSource, bool>
is used by pretty much all Queryable
and Enumerable
methods and extension methods... what's up with that?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
虽然
Predicate
与List
和Array
同时引入,但在 .net 2.0 中,不同的Func
和Action
变体来自 .net 3.5。因此,这些
Func
谓词主要用于 LINQ 运算符的一致性。 从 .net 3.5 开始,关于使用Func
和Action
指南状态:While
Predicate
has been introduced at the same time thatList<T>
andArray<T>
, in .net 2.0, the differentFunc
andAction
variants come from .net 3.5.So those
Func
predicates are used mainly for consistency in the LINQ operators. As of .net 3.5, about usingFunc<T>
andAction<T>
the guideline states:我以前也想过这个问题。 我喜欢
Predicate
委托 - 它很好且具有描述性。 但是,您需要考虑Where
的重载:这也允许您根据条目的索引进行过滤。 这很好而且一致,然而:
不会。
I've wondered this before. I like the
Predicate<T>
delegate - it's nice and descriptive. However, you need to consider the overloads ofWhere
:That allows you to filter based on the index of the entry as well. That's nice and consistent, whereas:
wouldn't be.
当然,使用
Func
而不是特定委托的实际原因是 C# 将单独声明的委托视为完全不同的类型。尽管
Func
和Predicate
都具有相同的参数和返回类型,但它们并不兼容赋值。 因此,如果每个库都为每个委托模式声明了自己的委托类型,那么这些库将无法互操作,除非用户插入“桥接”委托来执行转换。通过鼓励每个人使用 Func,微软希望这能够缓解委托类型不兼容的问题。 每个人的代表都会很好地合作,因为他们只是根据参数/返回类型进行匹配。
它并不能解决所有问题,因为
Func
(和Action
)不能有out
或ref
参数,但这些不太常用。更新: Svish 在评论中说道:
是的,只要您的程序仅将方法分配给委托,如我的
Main
函数的第一行所示。 编译器默默地生成代码来新建一个转发到该方法的委托对象。 因此,在我的Main
函数中,我可以将x1
更改为ExceptionHandler2
类型,而不会引起问题。但是,在第二行,我尝试将第一个委托分配给另一个委托。 即使认为第二个委托类型具有完全相同的参数和返回类型,编译器也会给出错误
CS0029:无法将类型“ExceptionHandler1”隐式转换为“ExceptionHandler2”
。也许这会让事情变得更清楚:
我的方法
IsNegative
非常适合分配给p
和f
变量,只要我这样做就这么直接。 但是我无法将其中一个变量分配给另一个变量。Surely the actual reason for using
Func
instead of a specific delegate is that C# treats separately declared delegates as totally different types.Even though
Func<int, bool>
andPredicate<int>
both have identical argument and return types, they are not assignment-compatible. So if every library declared its own delegate type for each delegate pattern, those libraries would not be able to interoperate unless the user inserts "bridging" delegates to perform conversions.By encouraging everyone to use Func, Microsoft is hoping that this will alleviate the problem of incompatible delegate types. Everyone's delegates will play nicely together, because they will just be matched up based on their parameter/return types.
It doesn't solve all problems, because
Func
(andAction
) can't haveout
orref
parameters, but those are less commonly used.Update: in the comments Svish says:
Yes, as long as your program only assigns methods to delegates, as in the first line of my
Main
function. The compiler silently generates code to new a delegate object that forwards on to the method. So in myMain
function, I could changex1
to be of typeExceptionHandler2
without causing a problem.However, on the second line I try to assign the first delegate to another delegate. Even thought that 2nd delegate type has exactly the same parameter and return types, the compiler gives error
CS0029: Cannot implicitly convert type 'ExceptionHandler1' to 'ExceptionHandler2'
.Maybe this will make it clearer:
My method
IsNegative
is a perfectly good thing to assign to thep
andf
variables, as long as I do so directly. But then I can't assign one of those variables to the other.建议(在 3.5 及以上版本中)是使用
Action<...>
和Func<...>
- 来回答“为什么?” - 一个优点是“Predicate
”仅在您知道“predicate”含义时才有意义 - 否则您需要查看对象浏览器(等)来查找签名。相反,
Func
遵循标准模式; 我可以立即看出这是一个接受T
并返回bool
的函数 - 不需要理解任何术语 - 只需应用我的真值测试即可。对于“谓词”,这可能没问题,但我很欣赏标准化的尝试。 它还允许与该领域的相关方法有很多相似之处。
The advice (in 3.5 and above) is to use the
Action<...>
andFunc<...>
- for the "why?" - one advantage is that "Predicate<T>
" is only meaningful if you know what "predicate" means - otherwise you need to look at object-browser (etc) to find the signatute.Conversely
Func<T,bool>
follows a standard pattern; I can immediately tell that this is a function that takes aT
and returns abool
- don't need to understand any terminology - just apply my truth test.For "predicate" this might have been OK, but I appreciate the attempt to standardise. It also allows a lot of parity with the related methods in that area.