簡體   English   中英

在可以修改的類上使用擴展方法是否可以接受

[英]Is it acceptable to use extension methods on a class which you can modify

我最近一直在考慮使用擴展方法在我控制的類上實現輔助工具(即,在同一個程序中,我可以修改)。 它背后的基本原理是,很多時候,這些輔助工具在非常特定的場景中使用,並且不需要訪問類的內部值。

例如,假設我有一個StackExchange類。 它有像PostQuestionSearchAnswerQuestion這樣的方法。

現在,如果我想手動計算我的聲譽以確保StackOverflow不會欺騙我,該怎么辦? 我會實現以下方面的內容:

int rep=0;
foreach(var post in StackExchangeInstance.MyPosts)
{
  rep+=post.RepEarned;
}

我可以向StackExchange類添加一個方法,但它不需要任何內部,並且它僅用於程序的一個或兩個其他部分。

現在想象一下,如果你有10或20個這些特定的輔助方法。 在某種情況下肯定有用,但絕對不適用於一般情況。 我的想法是改變像

public static RepCalcHelpers
{
  public static int CalcRep(StackExchange inst){ ... }
}

喜歡的東西

namespace Mynamespace.Extensions.RepCalculations
{
  public static RepCalcExtensions
  {
    public static int CalcRep(this Stackexchange inst){...}
  }
}

注意命名空間。 理想情況下,我會使用它來在特定場景中對擴展方法進行分組。 例如,“RepCalculations”,“Statistics”等。

我已經嘗試過搜索是否聽說過這種類型的模式,並且沒有找到任何擴展方法用於除了無法修改的類之外的任何證據的證據。

這種“模式”有哪些缺點? 我應該堅持繼承或組合,還是只是一個好的'靜態助手類?

我會閱讀有關擴展方法的框架設計指南部分。 是第二版作者之一的帖子。 您正在描述的用例(專門的幫助方法)被Phil Haack引用為擴展方法的有效用途,缺點是它需要額外的API知識才能找到那些“隱藏”方法。

該帖子中沒有提到,但書中建議擴展方法進入擴展類的單獨命名空間。 否則,它們將始終顯示為intellisense,並且無法將其關閉。

我想我已經在其他地方看到了這種模式。 它可能很混亂,但也非常強大。 這樣,您可以在庫中提供類,並在單獨的命名空間中提供一組擴展方法。 然后,無論誰使用您的庫,都可以選擇使用擴展方法導入命名空間或提供自己的擴展方法。

如果你有一些擴展方法只用於單元測試(例如,比較兩個對象在某種意義上是否相等,你只需要進行單元測試),那么這個模式的一個很好的選擇就是。

您似乎正在進行擴展方法等效於公共實例方法的比較。 它真的不是。

擴展方法只是一個公共靜態實用程序方法,碰巧有一個更方便的語法被調用。

所以首先我們要問自己,這個方法適合作為類本身的實例方法,或者它更適合作為外部類的靜態方法。 很少有類的用戶需要這個功能,因為它是高度本地化的而不是類本身執行的真正行為,而是由外部實體在類上執行的行為意味着它適合於它是靜態的。 主要的缺點是,如果有人擁有User並且想要重新計算他​​們的代表,那么它的行為可能更難找到。 現在,在這個特殊的情況下,它有點在柵欄上,你可以走另一條路,但我傾向於靜態方法。

現在我們已經確定它應該是靜態的,這是一個完全獨立的問題,它是否應該是一種擴展方法。 這更加主觀,並進入個人偏好領域。 這些方法是否可能被鏈接? 如果是這樣,擴展方法鏈接比嵌套調用靜態方法更好。 是否可能在使用它的文件中大量使用? 如果是,擴展方法可能會稍微簡化代碼,如果不是,它實際上沒有那么多幫助,甚至是傷害。 對於玩具示例,我可能會說我個人不會,但我不會對有人做過任何問題(畢竟你仍然可以使用擴展方法,就好像它是一個常規的公共靜態方法語法明智)。 對於一個非玩具的例子,它主要是個案決定。 關鍵是要注意你擴展的類,並問自己一個用戶是否願意混淆類型的Intellisense只是為了更方便地調用方法(這再次回到每個文件使用它的程度)在)。

還值得一提的是,有一些邊緣情況,擴展方法可以比實例化方法強大。 特別是通過利用類型推斷。 使用常規實例方法很容易接受該類型的類型或任何子類型,但有時返回傳入的類型而不是父類型是有用的。 這尤其適用於流暢的API。 這不是一個非常常見的例子,並且只與你的問題松散相關,所以我不會對此進行擴展。

在類實現接口並且您希望避免必須在實現相同接口的其他“future”類上實現相同方法的情況下,擴展方法可能非常有用。 例如,StackExchange實現了IStackExchange,ProgrammersExchange也實現了IStackExchange。 您的示例擴展方法僅用於實現CalcRep一次,而不必在兩個類上重新實現它。 這正是靜態Enumerable類中存在的所有擴展方法的原因。

除此之外,我沒有看到在你已經可以修改的類上使用擴展方法的令人信服的理由。 如果有的話,它的缺點是在重載解析過程中被認為是遲到的。

暫無
暫無

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

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