![](/img/trans.png)
[英]Why a `Predicate<T>` doesn't match a `Func<T,bool>`?
[英]Why Func<T,bool> instead of Predicate<T>?
這只是一個好奇的問題,我想知道是否有人有一個好的答案:
在 .NET 框架 Class 庫中,我們有例如這兩種方法:
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>
幾乎所有Queryable
和Enumerable
方法和擴展方法都使用......這是怎么回事?
雖然Predicate
與List<T>
和Array<T>
同時引入,但在 .net 2.0 中,不同的Func
和Action
變體來自 .net 3.5。
所以這些Func
謂詞主要用於 LINQ 運算符中的一致性。 從 .net 3.5 開始,關於使用Func<T>
和Action<T>
的指南指出:
請使用新的 LINQ 類型
Func<>
和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# 將單獨聲明的委托視為完全不同的類型。
盡管Func<int, bool>
和Predicate<int>
都具有相同的參數和返回類型,但它們不是賦值兼容的。 因此,如果每個庫都為每個委托模式聲明了自己的委托類型,那么除非用戶插入“橋接”委托來執行轉換,否則這些庫將無法互操作。
// 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
參數,但這些不太常用。
更新:在評論中 Svish 說:
盡管如此,將參數類型從 Func 切換到 Predicate 並返回,似乎沒有任何區別? 至少它仍然可以毫無問題地編譯。
是的,只要您的程序只將方法分配給代表,就像我的Main
function 的第一行一樣。 編譯器靜默生成代碼以新的委托 object 轉發到方法。 因此,在我的Main
function 中,我可以將x1
更改為ExceptionHandler2
類型而不會引起問題。
但是,在第二行,我嘗試將第一個代表分配給另一個代表。 即使認為第二個委托類型具有完全相同的參數和返回類型,編譯器也會給出錯誤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
分配給p
和f
變量是一件非常好的事情。 但是我不能將這些變量中的一個分配給另一個。
建議(在 3.5 及更高版本中)是使用Action<...>
和Func<...>
- 用於“為什么?” - 一個優點是“ Predicate<T>
”只有在您知道“謂詞”的含義時才有意義 - 否則您需要查看對象瀏覽器(等)以找到簽名。
相反Func<T,bool>
遵循標准模式; 我可以立即看出這是一個 function ,它接受一個T
並返回一個bool
- 不需要理解任何術語 - 只需應用我的真實性測試。
對於“謂詞”,這可能沒問題,但我很欣賞標准化的嘗試。 它還允許與該領域的相關方法進行大量對等。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.