簡體   English   中英

顯式地將派生類標記為基類的實現接口

[英]Explicitly marking derived class as implementing interface of base class

interface IBase
{
    string Name { get; }
}

class Base : IBase
{
    public Base() => this.Name = "Base";
    public string Name { get; }
}

class Derived : Base//, IBase
{
    public Derived() => this.Name = "Derived";
    public new string Name { get; }
}


class Program
{
    static void Main(string[] args)
    {
        IBase o = new Derived();
        Console.WriteLine(o.Name);
    }
}

在這種情況下,輸出將是“Base”。

如果我明確聲明 Derived 實現了 IBase(實際上已經由基類 Base 實現了,這樣的注釋似乎沒有用),輸出將是“Derived”

class Derived : Base, IBase
{
    public Derived() => this.Name = "Derived";
    public new string Name { get; }
}

這種行為的原因是什么?

VS 15.3.5,C# 7

它在 C# 5 規范的 13.4.4 到 13.4.6 節中進行了解釋。 下面引用了相關部分,但基本上,如果您明確聲明一個類實現了一個接口,則會再次觸發接口映射,因此編譯器將該類作為用來確定每個接口成員映射到哪個實現的類。

13.4.4 接口映射

類或結構必須提供在類或結構的基類列表中列出的所有接口成員的實現。 在實現類或結構中定位接口成員的實現的過程稱為接口映射。

類或結構的接口映射CC的基類列表中指定的每個接口的每個成員定位一個實現。 一個特定的接口部件的實現IM ,其中, I是其中成員的接口M被聲明時,通過檢查每個類或結構來確定S ,開始與C以及重復為每個相繼的基類的C ,直到發現匹配位於:

  • 如果S包含與IM匹配的顯式接口成員實現的聲明,則該成員是IM的實現。
  • 否則,如果S包含與 M 匹配的非靜態公共成員的聲明,則該成員是IM的實現。 如果有多個成員匹配,則未指定哪個成員是IM的實現。 僅當S是構造類型時才會發生這種情況,其中泛型類型中聲明的兩個成員具有不同的簽名,但類型參數使它們的簽名相同。

...

13.4.5 接口實現繼承

一個類繼承其基類提供的所有接口實現。 如果不顯式地重新實現接口,派生類就不能以任何方式改變它從基類繼承的接口映射。 例如,在聲明中

interface IControl { void Paint(); } class Control: IControl { public void Paint() {...} } class TextBox: Control { new public void Paint() {...} }

Paint在方法TextBox隱藏了Paint中的方法Control的,但它不會改變的映射Control.PaintIControl.Paint ,並調用Paint通過類實例和接口實例將具有以下效果

Control c = new Control(); TextBox t = new TextBox(); IControl ic = c; IControl it = t; c.Paint(); // invokes Control.Paint(); t.Paint(); // invokes TextBox.Paint(); ic.Paint(); // invokes Control.Paint(); it.Paint(); // invokes Control.Paint();

...

13.4.6 接口重新實現

通過將接口包含在基類列表中,允許繼承接口實現的類重新實現接口。

接口的重新實現遵循與接口的初始實現完全相同的接口映射規則。 因此,繼承的接口映射對為重新實現接口而建立的接口映射沒有任何影響。 例如,在聲明中

interface IControl { void Paint(); } class Control: IControl { void IControl.Paint() {...} } class MyControl: Control, IControl { public void Paint() {} }

ControlIControl.Paint映射到Control.IControl.Paint事實不會影響MyControl的重新實現,后者將IControl.Paint映射到MyControl.Paint

如果Derived未實現IBase並聲明new string Name ,則意味着Derived.NameIBase.Name在邏輯上不相同。 因此,當您訪問IBase.Name ,它會在Base類中查找它,實現IBase 如果刪除new string Name屬性,則輸出將為Derived ,因為現在Derived.Name = Base.Name = IBase.Name 如果您明確實現IBase ,則輸出將為Derived ,因為現在Derived.Name = IBase.Name 如果您將oDerived ,則輸出將為Derived ,因為現在您正在訪問Derived.Name而不是IBase.Name

暫無
暫無

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

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