[英]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 接口映射
類或結構必須提供在類或結構的基類列表中列出的所有接口成員的實現。 在實現類或結構中定位接口成員的實現的過程稱為接口映射。
類或結構的接口映射
C
為C
的基類列表中指定的每個接口的每個成員定位一個實現。 一個特定的接口部件的實現IM
,其中,I
是其中成員的接口M
被聲明時,通過檢查每個類或結構來確定S
,開始與C
以及重復為每個相繼的基類的C
,直到發現匹配位於:
- 如果
S
包含與I
和M
匹配的顯式接口成員實現的聲明,則該成員是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.Paint
到IControl.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() {} }
Control
將IControl.Paint
映射到Control.IControl.Paint
事實不會影響MyControl
的重新實現,后者將IControl.Paint
映射到MyControl.Paint
。
如果Derived
未實現IBase
並聲明new string Name
,則意味着Derived.Name
和IBase.Name
在邏輯上不相同。 因此,當您訪問IBase.Name
,它會在Base
類中查找它,實現IBase
。 如果刪除new string Name
屬性,則輸出將為Derived
,因為現在Derived.Name
= Base.Name
= IBase.Name
。 如果您明確實現IBase
,則輸出將為Derived
,因為現在Derived.Name
= IBase.Name
。 如果您將o
為Derived
,則輸出將為Derived
,因為現在您正在訪問Derived.Name
而不是IBase.Name
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.