簡體   English   中英

接口實現上成員的返回類型必須與接口定義完全匹配?

[英]The return type of the members on an Interface Implementation must match exactly the interface definition?

根據CSharp語言規范。

接口定義了可以通過類和結構實現的契約。 接口不提供它定義的成員的實現 - 它僅指定必須由實現接口的類或結構提供的成員。

所以我有這個:

interface ITest
{
    IEnumerable<int> Integers { get; set; }
}

我的意思是。 “我與一個屬性的合同是一個你可以枚舉的整數集合”。

然后我想要以下接口實現:

class Test : ITest
{
    public List<int> Integers { get; set; }
}

我得到以下編譯器錯誤:

'Test'沒有實現接口成員'ITest.Integers'。 'Test.Integers'無法實現'ITest.Integers',因為它沒有匹配的返回類型'System.Collections.Generic.IEnumerable'。

只要我可以說我的Test類實現了ITest契約,因為int屬性的List實際上是int的IEnumerable。

那么c#編譯器告訴我錯誤的方式呢?

僅供參考,您想要的功能稱為“虛方法返回類型協方差”,正如您所發現的那樣,C#不支持它。 它是其他面向對象語言的一個特性,比如C ++。

雖然我們經常收到此功能的請求,但我們沒有計划將其添加到該語言中。 這不是一個可怕的特征; 如果我們擁有它,我會使用它。 但是我們有很多理由不這樣做,包括CLR不支持它,它為可版本化的組件添加了新的和有趣的故障模式,Anders認為它不是一個非常有趣的功能,而且我們有很多很多更高的優先級和有限的預算。

順便說一下,盡管人們一直要求我們使用虛方法返回類型協方差,但是沒有人要求虛方法形式參數類型相反 ,即使邏輯上它們本質上是相同的特征。 也就是說,我有一個帶有長頸鹿的虛擬方法/接口方法M,我想用一個帶動物的方法M來覆蓋/實現它。

你不能這樣做是因為你手上有一個重大問題,具體取決於實施情況,如果這是允許的話。 考慮:

interface ITest
{
    IEnumerable<int> Integers { get; set; }
}

class Test : ITest
{
    // if this were allowed....
    public List<int> Integers { get; set; }
}

這將允許:

ITest test = new Test();
test.Integers = new HashSet<int>();

這會使Test的合同無效,因為Test說它包含List<int>

現在,您可以使用顯式接口實現來允許它滿足這兩個簽名,具體取決於它是從ITest引用還是Test引用調用:

class Test : ITest
{
    // satisfies interface explicitly when called from ITest reference
    IEnumerable<int> ITest.Integers
    {
        get
        {
            return this.Integers; 
        }
        set
        {
            this.Integers = new List<int>(value);
        }
    }

    // allows you to go directly to List<int> when used from reference of type Test
    public List<int> Integers { get; set; }
}

簡單的事實是,如果界面說:

IInterface{
   Animal A { get; }
}

然后該屬性的實現必須與該類型完全匹配 試圖將其實現為

MyClass : IInterface{
  Duck A { get; }
}

不起作用 - 即使DuckAnimal

相反,你可以這樣做:

MyClass : IInterface{
  Duck A { get; }
  Animal IInterface.A { get { return A; } }
}

即提供IInterface.A成員的顯式實現,利用DuckAnimal之間的類型關系。

在你的情況下,這意味着至少實現吸氣劑,ITest.Integers為

IEnumerable<int> ITest.Integers { get { return Integers; } }

要實現setter,您需要樂觀地投射或在輸入值上使用.ToList()。

請注意,在這些顯式實現中使用AIntegers不是遞歸的,因為顯式接口實現在類型的公共視圖中是隱藏的 - 它們僅在調用者通過它的IInterface / ITest接口實現與該類型進行通信時IInterface

您需要規范中的13.4.4:

出於接口映射的目的,類成員A匹配接口成員B

AB的性質,A和B的名稱和類型相同的 ,和A具有相同的訪問BA允許有額外的訪問器,如果它不是顯式接口成員實現)。

另外,您認為List<int> Integers { get; set; } List<int> Integers { get; set; } List<int> Integers { get; set; }滿足合同IEnumerable<int> Integers { get; set; } IEnumerable<int> Integers { get; set; } IEnumerable<int> Integers { get; set; }是假的。 即使規范以某種方式放寬而不要求返回類型相同,請注意具有公共setter的List<int>類型的屬性與具有公共setter的IEnumerable<int>類型的屬性不同。因為對於后者你可以分配一個int[]的實例,但對於前者你不能。

你可以這樣做:

 interface ITest
{
    IEnumerable<int> Integers { get; set; }
}

class Test : ITest
{
    public IEnumerable<int> Integers { get; set; }

    public Test()
    {
        Integers = new List<int>();
    }
}

因為Test不是ITest。 為什么? 使用ITest,您可以將數組設置為屬性Integers。 但你不能用一個測試。 使用.net 4.0,你可以做那樣的事情(協方差和反方差)但不完全是這樣,它在每種語言中都是不正確的。

暫無
暫無

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

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