2009-10-27 47 views
0

所以我一直在處理最近由不同軟件供應商爲他們的產品提供的幾個API。有時候缺乏一些東西,有時候我只想讓代碼更具可讀性,並且我試圖避免大量的靜態方法,它們不屬於API中「我需要的東西」。因此,我發現自己寫了很多擴展方法。擴展「類」:很好地使用擴展方法並提高代碼可讀性......或難聞的氣味?

然而,因爲有很多的方法,並在保持黨的利益「我」的方法從這些代碼可讀性方面的API對象分開,我想出了這個小珍聞:

public class MyThirdPartyApiExtensionClass { 

    public static MyThirdPartyApiExtensionClass MTPAEC(this ThirdPartyApiClass value) { 
     return new MyThirdPartyApiExtensionClass(value); 
    } 

    private ThirdPartyApiClass value; 

    public MyThirdPartyApiExtensionClass(ThirdPartyApiClass extendee) { 
     value = extendee; 
    } 

    public string SomeMethod() { 
     string foo = value.SomeCrappyMethodTheProviderGaveUs(); 
     //do some stuff that the third party api can't do that we need 
     return foo; 
    } 

    public int SomeOtherMethod() { 
     int bar = value.WowThisAPISucks(null); 
     //more stuff 
     return bar; 
    } 

} 

然後我可以做這樣的事情:

string awesome = instanceOfApiObject.MTPAEC.SomeMethod(); 

和我有一個乾淨的我的東西從他們的分離。

現在我的問題是......這似乎是一個很好的做法,提高了代碼的可讀性......或者這是一個壞主意嗎?這樣做會有什麼不良後果嗎?

聲明: 上面的代碼只是爲了演示這個概念。顯然,在真實的事情中有更好的理智檢查和有用性。

編輯: 我想分離的相同水平可以簡單地做這樣的:

public static class MyThirdPartyApiExtensionClass { 

    public ThirdPartyApiClass MTPAEC(this ThirdPartyApiClass value) { 
     return value; 
    } 

    public string SomeMethod(this ThirdPartyApiClass value) { 
     string foo = value.SomeCrappyMethodTheProviderGaveUs(); 
     //do some stuff that the third party api can't do that we need 
     return foo; 
    } 

    public int SomeOtherMethod(this ThirdPartyApiClass value) { 
     int bar = value.WowThisAPISucks(null); 
     //more stuff 
     return bar; 
    } 

} 
+0

它基本上是一個適配器模式,在擴展方法的幫助下使代碼更具可讀性。擴展方法在用於此目的時,基本上是適配器模式的改進版本。 – snicker 2009-10-27 17:39:13

+0

我不確定這會實際上起作用。我相信擴展方法要求擴展類聲明爲靜態的。你可能需要兩個類。 – 2009-10-27 17:47:33

+0

我也是相當積極的靜態類不能有非靜態成員。 – 2009-10-27 17:50:54

回答

2

爲了回答您的直接問題,我認爲,經歷額外的麻煩將功能從基本功能中分離出來是一種糟糕的代碼異味。從使用的角度來看,不要擔心代碼與代碼分離。首先,它使得找到你要找的東西更加困難,因爲現在有兩個地方可以尋找相同的功能,其次,語法使得它看起來像你的擴展在MTPAEC屬性上運行而不是核心對象(它們是是)。

我的建議是使用實際的擴展方法,它允許你有那個,但沒有額外的構造函數。

public static class ApiExtension 
{ 
    public static string SomeMethod(this ThirdPartyApiClass value) 
    { 
     string foo = value.SomeCrappyMethodTheProviderGaveUs(); 
     //do some stuff that the third party api can't do that we need 
     return foo; 
    } 
} 

使用

var mine = new ThirdPartyApiClass(); 
mine.SomeMethod(); 

C#將做休息。

看着你的上面的建議,你將不得不把我想的兩門課分開。一個用於使用擴展機制提供擴展組,另一個用於提供每組邏輯。

如果您需要一目瞭然然後使用命名約定來使您的外觀獨特。雖然在盤旋和通過智能感知它會告訴你,這是一種擴展方法。

如果你只是想分離你喜歡的內容,那麼你需要兩個類。

public static class ApiExtensionder 
{ 
    public static MTPAEC(this ThirdPartyApiClass value) 
    { 
     return new MtpaecExtensionWrapper(value); 
    } 
} 

public class MtpaecExtensionWrapper 
{ 
    private ThirdPartyApiClass wrapped; 

    public MtpaecExtensionWrapper(ThirdPartyApiClass wrapped) 
    { 
     this.wrapped = wrapped; 
    } 

    public string SomeMethod() 
    { 
     string foo = this.wrapped.SomeCrappyMethodTheProviderGaveUs(); 
     //do some stuff that the third party api can't do that we need 
     return foo; 
    } 
} 
+0

這完全繞過了我發佈問題的原始原因。我明白擴展方法是如何工作的,我只是在代碼中尋找額外的分隔。 IE立即知道thirdPartyApiClass.MTPAEC.Method()立即屬於我,而thirdPartyApiClass.Method()並不那麼明顯。 – snicker 2009-10-27 17:37:40

+0

@snicker:然後使用命名約定,如果你喜歡。儘管intellisense會告訴你,這是一種擴展方法,而不是本地方法。 – 2009-10-27 17:41:12

2

當你不能修改API處理,擴展方法是延長一種合理的方式API的表現力,同時保持相對解耦,恕我直言。

擴展方法的最大問題與它隱式推斷爲基於命名空間包含(文件頂部的using語句)可用的事實有關。因此,如果你忘記包含一個命名空間,你最終可能會抓住你的頭腦,想知道爲什麼沒有可用的東西。

我還會補充說,擴展方法並不是一個明顯的構造,因此開發人員通常不會期望或期待它們。但是,隨着LINQ的使用越來越多,我會想象越來越多的開發人員會習慣使用它們。

0

我的意見是你不必要地增加了一個額外的間接級別。你希望擴展方法在原始對象上可用......那麼爲什麼不把它們放在那裏呢?智能感知會讓你知道對象是擴展名,對於你真正關心的罕見情況。

+0

除了代碼可讀性和更大的分隔外,沒有其他目的。 – snicker 2009-10-27 17:29:58