2011-08-14 24 views
8

我最近決定將刷新我的關於C#基礎知識記憶,所以這可能是微不足道的,但我已經碰到了以下問題:C#協變和逆變實施時接口

StringCollection在.NET V1使用2.0中以創造,而不是一個object基於ArrayList字符串強類型集合(這後來被包括泛型集合增強):

StringCollection定義以快速瀏覽,你可以看到如下:

// Summary: 
//  Represents a collection of strings. 
[Serializable] 
public class StringCollection : IList, ICollection, IEnumerable 
{ 
... 
    public int Add(string value); 
... 
} 

你可以看到它實現IList,其中包含以下聲明(一些其他的聲明中):

int Add(object value); 

但不是:

int Add(string value); 

我的第一個假設是,這是可能的,因爲.NET框架協方差規則。

所以,以確保公正,我試着寫我自己的類,它實現IList和改變

int Add(object value); 

檢索字符串類型,而不是一個對象類型,但我驚訝的是,試圖編譯項目時,我得到了一個編譯時錯誤:

does not implement interface member 'System.Collections.IList.Add(object)' 

任何想法是什麼原因造成的?

謝謝!

回答

7

該行爲是由明確實施IList.Add(object)而不是共同/反對導致的。根據MSDN文檔,StringCollection顯式實現了IList.Add(object); Add(string)方法是不相關的。實現可能類似於這樣的事情:

class StringCollection : IList 
{ 
    ... 
    public int Add(string value) 
    {} // implementation 

    public int IList.Add (object value) 
    { 
     if (!value is string)) return -1; 
     return Add(value as string) 
    } 
} 

這種區別可以看出:

StringCollection collection = new StringCollection(); 
    collection.Add(1); // compile error 
    (collection as IList).Add(1); // compiles, runtime error 
    (collection as IList).Add((object)"") // calls interface method, which adds string to collection 

附錄

的,爲什麼這種模式實現上面並沒有解決。 C#語言規範規定[§13.4.1,強調]:

In some cases, the name of an interface member may not be appropriate for the implementing class, in which case the interface member may be implemented using explicit interface member implementation. [...]

It is not possible to access an explicit interface member implementation through its fully qualified name in a method invocation, property access, or indexer access. An explicit interface member implementation can only be accessed through an interface instance, and is in that case referenced simply by its member name.

StringCollection堅持到所需的IList的行爲 - 的IList不保證任意對象可以被添加到它。 StringCollection提供了更強的保證 - 主要是它將只包含字符串。該類包括其自己的強類型方法,用於Add,Contains,Item以及其他標準用例,其中它作爲StringCollection而不是IList進行訪問。但它仍然可以很好地工作,如接受並返回對象,但如果嘗試添加不是字符串的項目,則會返回錯誤代碼(如IList所允許的那樣)IList

最終,界面是否顯示在類中(即明確實現)是由類作者決定的。在框架類的情況下,顯式實現包含在MSDN文檔中,但不能作爲類成員訪問(例如,在自動完成上下文中顯示)。

+0

所以我應該記住,作爲一個經驗法則,顯式實現的接口不會顯示在.NET庫的內置類定義中? (因爲我顯然無法在StringCollection類的所有方法中看到此實現) 任何原因爲什麼? –

+0

一般來說,實際上類似於會員投影 - 我修改了迴應來解決這個問題。 – drf

0

如果您使用的是.NET 2.0+,我只是將使用泛型:

IList<string> list = new List<string>(); 

這應該給你你想要的一切。

0

IList.Add(object)可以接受字符串以外的參數 - 它可以接受任何類型。所以如果你聲明你的接口的實現只接受字符串,它不再符合接口規範,因爲現在我無法傳入Stream例如。

方差可以工作其他方式:如果被聲明爲接受字符串的界面的方法,然後接受對象將是正常的,因爲字符串也是對象,並且因此任何輸入到接口的方法也將是可接受的輸入到你的實現。 (但是,您仍然必須提供一個接受字符串的方法的顯式接口實現,因爲在C#中接口方法實現與接口方法聲明非常匹配。)

0

基本上指定的是Add,傳遞任何對象作爲參數,從盒裝Int到另一個IListSystem.DivideByZeroException。如果您只提供Add(string)方法,則由於只能添加字符串,因此尚未滿足此要求。

換句話說,您將無法撥打StringCollection.Add(new Object());,如果界面正確實施,應該完全可行。:D