2013-03-19 173 views
10

時,爲什麼我不能使用兼容的具體類型,我希望能夠做這樣的事情:實現接口

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace Test 
{ 
    public interface IFoo 
    { 
     IEnumerable<int> integers { get; set; } 
    } 

    public class Bar : IFoo 
    { 
     public List<int> integers { get; set; } 
    } 
} 

爲什麼編譯器會抱怨..?

Error 2 'Test.Bar' does not implement interface member 'Test.IFoo.integers'. 'Test.Bar.integers' cannot implement 'Test.IFoo.integers' because it does not have the matching return type of 'System.Collections.Generic.IEnumerable<int>'. 

據我所知,接口說IEnumerable和類使用列表,但列表一個IEnumerable .....

我能做些什麼?我不想在類中指定IEnumerable,我想使用實現IEnumerable的具體類型,如列表...

+2

「我想使用實現IEnumerable的具體類型,像List ...「 - 爲什麼? – jcollum 2013-03-19 02:43:45

回答

12

這是一個類型協方差/逆變問題(請參閱http://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)#C.23)。

有一個變通方法:使用顯式接口,就像這樣:

public class Bar : IFoo { 

    private IList<int> _integers; 

    IEnumerable<int> IFoo.integers { 
     get { return _integers }; 
     set { _integers = value as IList<int>; } 
    } 

    public IList<int> integers { 
     get { return _integers; } 
     set { _integers = vale; } 
    } 
} 

注意integers應TitleCased符合.NET的準則。

希望您可以在上面的代碼中看到問題:IList<int>僅與訪問器的IEnumerable<int>兼容,但不適用於設置。如果有人撥打IFoo.integers = new Qux<int>()(其中Qux : IEnumerable<int>而不是Qux : IList<int>)會發生什麼情況。

+0

在處理將JSON對象反序列化爲必須具有接口參數的具體對象時,這變得非常有用。通過提供具體參數,解串器可以找出一種方法來實例化參數的對象。 – 2013-08-09 15:48:55

4

雖然List實現IEnumerable,但這不是接口的工作方式。該接口準確指定哪些類型需要公開屬性。如果你創建了一個通用的接口一樣

public interface IFoo<T> where T : IEnumerable<int> 
{ 
    T integers { get; set; } 
} 

然後,您可以使用IFoo<List<int>>實現它在你希望的方式。

3

除非您在幕後操作,否則您將無法使用具體類型。問題是你可以同時獲取和設置屬性。

您的界面指定該屬性的類型爲IEnumerable<int>HashSet<int>執行IEnumerable<int>。這意味着下面的應該只是罰款:

IFoo instance = new Bar(); 
instance.integers = new HashSet<int>(); 

但既然你要實現使用具體類型List<int>接口,有沒有辦法,可以分配工作。

最簡單的修復,假設你不經常需要重新分配的集合,是隻爲集合指定一個getter:

public interface IFoo 
{ 
    IEnumerable<int> Integers { get; } 
} 

public class Bar 
{ 
    public List<int> Integers { get; private set; } 

    public Bar(List<int> list) 
    { 
     Integers = list; 
    } 
} 
+0

我認爲這有效(我現在無法測試),但我不明白爲什麼。爲什麼從接口移除setter允許'List '實現'IEnumerable '?編譯器是否在每個方向進行類型檢查(即你可以實現一個'List Integers {set; }'用IEnumerable 整數{private get;設置}? – Bobson 2013-03-19 03:53:22

+0

我假設示例代碼中的'Bar'實現了'IFoo'?如果是這樣,代碼不能解決問題。相同的編譯錯誤:'Test.Bar.Integers'無法實現Test.IFoo.Integers',因爲它沒有匹配的返回類型'System.Collections.Generic.IEnumerable ''。我錯過了什麼嗎? – Peter 2015-04-23 18:06:37