簡體   English   中英

為什么選擇 Func<t,bool> 而不是謂詞<t> ?</t></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>幾乎所有QueryableEnumerable方法和擴展方法都使用......這是怎么回事?

雖然PredicateList<T>Array<T>同時引入,但在 .net 2.0 中,不同的FuncAction變體來自 .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 )不能有outref參數,但這些不太常用。

更新:在評論中 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分配給pf變量是一件非常好的事情。 但是我不能將這些變量中的一個分配給另一個。

建議(在 3.5 及更高版本中)是使用Action<...>Func<...> - 用於“為什么?” - 一個優點是“ Predicate<T> ”只有在您知道“謂詞”的含義時才有意義 - 否則您需要查看對象瀏覽器(等)以找到簽名。

相反Func<T,bool>遵循標准模式; 我可以立即看出這是一個 function ,它接受一個T並返回一個bool - 不需要理解任何術語 - 只需應用我的真實性測試。

對於“謂詞”,這可能沒問題,但我很欣賞標准化的嘗試。 它還允許與該領域的相關方法進行大量對等。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM