C# 为什么是Func<;T、 布尔>;而不是谓词<;T>;?
这只是一个好奇的问题,我想知道是否有人有一个好的答案: 例如,在.NET Framework类库中,我们有以下两种方法:C# 为什么是Func<;T、 布尔>;而不是谓词<;T>;?,c#,.net,predicate,func,C#,.net,Predicate,Func,这只是一个好奇的问题,我想知道是否有人有一个好的答案: 例如,在.NET Framework类库中,我们有以下两种方法: public static IQueryable<TSource> Where<TSource>( this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate ) public static IEnumerab
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
)
公共静态IQueryable,其中(
这是可靠的消息来源,
表达式谓词
)
公共静态IEnumerable在哪里(
这是一个数不清的来源,
Func谓词
)
为什么他们使用
Func
而不是谓词
?似乎谓词
仅由列表
和数组
使用,而函数
几乎被所有可查询
和可枚举
方法和扩展方法使用。。。这是怎么回事?虽然谓词
是在列表
和数组
的同时引入的,但在.net 2.0中,不同的函数
和动作
变体来自.net 3.5
因此,这些Func
谓词主要用于LINQ运算符中的一致性。从.net 3.5开始,关于使用Func
和Action
务必使用新的LINQ类型Func
和
表达式
而不是自定义
委托和谓词
我以前就想知道这一点。我喜欢
谓词
委托-它很好而且具有描述性。但是,您需要考虑<代码>的重载,其中< /C> >:
Where<T>(IEnumerable<T>, Func<T, bool>)
Where<T>(IEnumerable<T>, Func<T, int, bool>)
其中(IEnumerable,Func)
其中(IEnumerable,Func)
这也允许您根据条目的索引进行筛选。这很好,而且前后一致,然而:
Where<T>(IEnumerable<T>, Predicate<T>)
Where<T>(IEnumerable<T>, Func<T, int, bool>)
Where(IEnumerable,谓词)
其中(IEnumerable,Func)
不可能。建议(在3.5和更高版本中)使用操作和函数来解释“为什么?”-一个优点是“谓词
”只有在您知道“谓词”的含义时才有意义-否则您需要查看对象浏览器(etc)来查找符号
相反地,Func
遵循标准模式;我可以立即看出,这是一个函数,它接受一个T
,并返回一个bool
——不需要理解任何术语——只要应用我的真值测试即可
对于“谓词”,这可能还可以,但我很欣赏标准化的尝试。它还允许与该领域中的相关方法进行大量对等。使用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,微软希望这将缓解委托类型不兼容的问题。每个人的代理都会很好地配合,因为它们只会根据其参数/返回类型进行匹配
它不能解决所有问题,因为Func
(和Action
)不能有out
或ref
参数,但这些参数不太常用
更新:斯维什在评论中说:
不过,从
Func to谓词和
回来,似乎没什么意义
区别?至少它还能编译
没有任何问题
是的,只要您的程序只为代理分配方法,就像我的Main
函数的第一行一样。编译器以静默方式生成代码,将新的委托对象转发给该方法。因此,在我的Main
函数中,我可以将x1
更改为ExceptionHandler2
类型,而不会引起问题
但是,在第二行,我尝试将第一个委托分配给另一个委托。即使第二个委托类型具有完全相同的参数和返回类型,编译器也会给出错误CS0029:无法将类型“ExceptionHandler1”隐式转换为“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
}
公共静态bool为负(int x)
{
返回x<0;
}
静态void Main(字符串[]参数)
{
谓语p=IsNegative;
Func f=负;
p=f;//不允许
}
我的方法IsNegative
非常适合分配p
和f
变量,只要我直接这样做。但是我不能将这些变量中的一个分配给另一个。酷,以前从未见过这些Guillideline=)会接受这个答案,因为它拥有最多的选票。因为Jon Skeet有很多代表性这是一个奇怪的指导方针。当然,它应该声明“确实使用新的LINQ类型”Func“和”Action“[…]”。表达式是一个完全不同的东西。实际上,您必须将它放在指南的上下文中,这是关于编写LINQ提供程序的。是的,对于LINQ操作符,准则是使用Func和Expression作为扩展方法的参数。我同意,我希望有一个单独的关于使用Func和action的指南。我认为Skeet的观点是,表达式不是指南。这是C#编译器的一项功能,用于识别该类型并对其执行不同的操作。谓词会有点难看——谓词通常(计算机科学的IME)基于单个值进行谓词。当然可以是谓词,但那更难看:)真的。。。呵呵。不,我想Func比较干净。因为指南,我接受了另一个答案。但愿我能记下不止一个答案!如果我能将一些答案标记为“非常值得注意”或“除了答案之外还有一个值得注意的要点”,那就太好了。嗯,我刚刚看到我把第一条评论写错了:P我的建议当然是谓词…@JonSkeet I