簡體   English   中英

為什么必須明確實現此接口?

[英]Why does this interface have to be explicitly implemented?

幾年后回到C#所以我有點生疏了。 遇到這個(簡化的)代碼,它讓我頭疼。

為什么必須顯式實現IDataItem.Children屬性? 普通的Children財產是否滿足要求? 畢竟,該屬性直接用於滿足它。 為什么不隱含?

public interface IDataItem {

    IEnumerable<string> Children { get; }
}

public class DataItem : IDataItem {

    public Collection<string> Children { get; } = new Collection<string>();

    // Why doesn't 'Children' above implement this automatically?!
    // After all it's used directly to satisfy the requirement!
    IEnumerable<string> IDataItem.Children => Children;
}

根據C#源代碼,這里是Collection<T>的定義:

[System.Runtime.InteropServices.ComVisible(false)]
public class Collection<T> :
    System.Collections.Generic.ICollection<T>,
    System.Collections.Generic.IEnumerable<T>, <-- Right Here
    System.Collections.Generic.IList<T>,
    System.Collections.Generic.IReadOnlyCollection<T>,
    System.Collections.Generic.IReadOnlyList<T>,
    System.Collections.IList

正如你所看到的,它明確地實現了IEnumerable<T> ,根據我的理解,如果'X'實現'Y'然后'X' 'Y',那么Collection<String> 一個IEnumerable<String>所以我是不確定為什么不滿意。

也許這個例子讓它更清晰。 我們希望簽名完全匹配1,2 ,不允許任何替換,盡管類型之間存在任何繼承關系。

我們不允許寫這個:

public interface IDataItem {

    void DoStuff(string value);
}

public class DataItem : IDataItem {

    public void DoStuff(object value) { }
}

你的例子是相同的,除了你要求返回類型而不是參數(並采用縮小而不是加寬轉換,原因很明顯)。 盡管如此,同樣的原則也適用。 在匹配簽名時,類型必須完全匹配3

您可以要求提供允許此類事件發生的語言,並且可能存在此類語言。 但事實是,這些是C#的規則。


1除了涉及泛型和接口/ delgates的Co和Contra-variance的一些有限支持之外。

2有些人可能會爭論簽名是否是在這里使用的正確詞匯,因為在這種情況下 ,返回類型與參數類型,通用arity等一樣重要; 在大多數其他人談論C#方法簽名的情況下,他們將明確忽略返回類型,因為他們(明確地或隱含地)考慮重載規則所說的內容,並且對於重載,返回類型不是簽名的一部分。

盡管如此,我對我在這里使用“簽名”一詞感到滿意。 簽名未在C#規范中正式定義,並且在使用它的地方,通常會指出簽名的哪些部分被考慮用於重載。

3更不用說如果您的Children方法返回一個碰巧實現IEnumerable<string>struct ,將會引發的問題。 現在你有了一個返回值類型和調用者值的方法(通過IDataItem接口,它希望接收對象的引用)

因此,該方法甚至不能按原樣使用。 我們必須(在這種情況下) 隱藏裝箱轉換來實現接口。 當推測C#的這一部分時,我相信它們不會為你自己可以輕易編寫的代碼設置太多“隱藏的魔力”。

在您的示例中,您的“普通”Children屬性實際上並不滿足接口要求。 類型不同。 你可以施展它並不重要 - 它們是不同的。

類似的例子,也許更明顯的是,如果你將實現一個接口,其實際方法返回IEnumerable並嘗試從實際類中的ICollection方法。 仍然存在編譯時錯誤。

正如@Ben Voigt所說,轉換仍會產生一些代碼,如果你想擁有它 - 你需要隱式添加它。

這里已經回答了這個問題(你必須匹配接口類型),我們可以用一個例子來演示這個問題。 如果這有效:

public interface IDataItem {

    IEnumerable<string> Children { get; set; }

    void Wipe();
}

public class DataItem : IDataItem {

    public Collection<string> Children { get; } = new Collection<string>(); 

    public void Wipe() {
        Children.ClearItems();  //Property exists on Collection, but not on IEnumerable
    }
}

然后我們使用這樣的代碼:

IDataItem x = new DataItem();

//Should be legal, as Queue implements IEnumerable. Note entirely sure
//how this would work, but this is the system you are asking about.
x.Children = new Queue<string>();

x.Wipe();  // Will fail, as Queue does not have a ClearItems method within

您要么意味着該屬性只能枚舉,要么您需要Collection類的屬性 - 適當地鍵入您的接口。

任何實現接口的類都必須包含與接口指定的簽名匹配的方法的定義。 界面僅定義簽名。 這樣,C#中的接口類似於抽象類,其中所有方法都是抽象的。

接口可以包含方法,屬性,事件,索引器或這四種成員類型的任意組合。

這是關於接口的好讀物。 C#中的接口

希望它能幫助你進一步理解。

暫無
暫無

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

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