2010-09-28 40 views
6

問這個問題的更好的方法將是一個例子如下 這兩種方法的優缺點是什麼?一個人總是比另一個人好還是在特定情況下?如果使用Approach1,使用一個接口將會是正確的嗎?因爲任何人都可以訪問公共方法?如果使用接口,應該一個類總是嚴格執行一個接口

public interface IDoSomething 
{ 
    void Method1(string operation, User user, string category) 
    void Method2(string operation, User user) 
    void Method3(string operation) 
} 

//Approach1 
Class A: IDoSomething 
{        
    public void Method1(string operation, User user, string category) 
    { 
    //do some db logic here... 
    } 

    public void Method2(string operation, User user) 
    { 
    Method1(operation, user, "General"); 
    } 

    public void Method3(string operation) 
    { 
    Method1(operation, User.GetDefaultUser(), "General"); 
    } 
} 

OR

//Approach2 
Class A: IDoSomething 
{        
    void IDoSomething.Method1(string operation, User user, string category) 
    { 
    //do some logic here... 
    } 

    void IDoSomething.Method2(string operation, User user) 
    { 
    (this as IDoSomething).Method1(operation, user, "General"); 
    } 

    void IDoSomething.Method3(string operation) 
    { 
    (this as IDoSomething).Method1(operation, User.GetDefaultUser(), "General"); 
    } 
} 

回答

7

您正在尋找的用於描述第二種方法的短語是顯式接口實現。就個人而言,我大部分時間都不會使用它。如果您需要以不同方式實現具有相同成員簽名的不同界面,或者您想要限制某些成員到,那麼只有在處理接口類型表達式時纔會看到 ......但這可能會很痛苦如果因爲某種原因你的主叫方有具體的類型,並且需要撥打一些類型特定的方法和一些接口方法。您甚至無法在相同的內看到明確實施的方法,而無需將this轉換爲接口類型。

顯式接口實現也意味着你不能覆蓋接口方法 - 你必須在任何子類中重新實現接口。基本上它最終會變得非常複雜 - 所以如果可能的話,我會避免它。

一個最後注意:顯式接口的實現也是plays badly with dynamic in C# 4

+0

哇,不知道顯式實現沒有繼承。有趣的知道。 – 2010-09-28 16:34:18

+0

@達倫:這些方法是繼承的,但不是以可覆蓋的方式 - 它們永遠不是虛擬的。說實話,這有點奇怪。 – 2010-09-28 16:43:31

+0

想要重寫本身就是一個強烈的表示,即成員應該是公開的,或者至少直接調用派生類(可能是前者)可見的東西。 – 2010-09-28 16:53:47

0

它是(在一定程度上)的口味的問題。主要的區別是,如果你做出明確的實施,這些方法不能被調用,除非你先投的對象接口類型:

A item = new A(); 
item.Method2(operation, user); // will not compile 
(item As IDoSomething).Method2(operation, user); // works well 

,如果你不想要的接口實現此方法非常有用由於某種原因在IntelliSense中「混亂」成員列表。

就我個人而言,我傾向於使用隱式方法,除非有特定的理由來「隱藏」接口實現。

2

方法1是天然在C#中實現接口的方式。如果你寫一個圖書館,這是你的客戶期望的;如果你自己使用這個類,那麼在調用這些方法時可以節省大量的投射。

使用方法2(explicit interface implementation)如果你有好理由這樣做。良好的原因可能包括

  • 實現多個接口共享相同的方法簽名(但需要不同的實現),
  • 方法名,對於接口的意義,但可能會誤導你的班級。
0

兩個非常普遍的組合是實施IEnumerable<T>時。由於IEnumerable<T>繼承自IEnumerable,因此您必須實現IEnumerable<T>.GetEnumerator()IEnumerable.GetEnumerator()。由於這些返回類型不同,但匹配參數列表(空),所以最多隻能隱式實現一個。

最常見的模式是實現通用版:

public IEnumerator<T> GetEnumerator() 
{ 
    //some code that returns an appropriate object. 
} 
IEnumerator IEnumerable.GetEnumerator() 
{ 
    return GetEnumerator();//return the result of the other call. 
} 

現在,一個不需要有任何的暗示或一個可以(有位在明確實現鑄造的)有這樣的其他方式周圍。然而,這是由於以下原因更加得心應手:

  1. 我們可能寧願隱式版本叫做,因爲它可能有更好的類型安全,也許更好的效率,如果枚舉器對象通過其多處理顯式接口。
  2. 隱式版本將爲需要IEnumerator<T>的調用代碼和需要IEnumerator的調用代碼提供服務(因爲這是隱式強制轉換),因此是最有用的。

現在,這種情況是我們被迫使用顯式接口的情況之一。例如,我們可能會選擇一個案例,請考慮編寫一個包含List<T>的只讀列表並實施IList<T>

我們所必須做的,是委派的讀操作的包裹列表,並拋出不支持寫入操作,例如:

public T this[int idx] 
{ 
    get 
    { 
    return _inner[idx]; 
    } 
    set 
    { 
    throw new NotSupportedException("Read only list."); 
    } 
} 
public int Count 
{ 
    get 
    { 
    return _inner.Count; 
    } 
} 
public void Add(T item) 
{ 
    throw new NotSupportedException("Read only list."); 
} 
public bool IsReadOnly 
    { 
    get 
    { 
    return false; 
    } 
} 

等。然而,這對於使用具體類型的對象來說並不是很有用,我們有大量的成員返回相同的結果(IsReadOnly)或者總是拋出異常。雖然通過接口使用類的代碼必須能夠調用這些方法和屬性,但在具體類中這樣做沒有任何價值。因此,我們可以做如下:

public T this[int idx] 
{ 
    get 
    { 
    return _inner[idx]; 
    } 
} 
T IList<T>.this[int index] 
{ 
    get { return this[index]; } 
    set { throw new NotSupportedException("Collection is read-only."); } 
} 
public int Count 
{ 
    get 
    { 
    return _inner.Count; 
    } 
} 
void ICollection<T>.Add(T item) 
{ 
    throw new NotSupportedException("Read only list."); 
} 
bool ICollection<T>.IsReadOnly 
    { 
    get 
    { 
    return false; 
    } 
} 

現在,當我們全面貫徹IList<T>,我們還提供了一個更清潔,更實用的接口(在一般的而不是C#具體的「接口」的意義上)的具體類的用戶。

請注意,這正是建立在它通常更有意義隱含的原因上:我們讓所有這些成員對於具體類的用戶來說更加尷尬(這些代碼必須投射到IList<T>第一)。這在這裏很好,因爲這種尷尬的代碼的唯一結果是毫無意義或危險的,並且讓糟糕的想法更難做是件好事。如果這種尷尬只是阻礙,那將是另一回事。

相關問題