显式地将派生类标记为基类的实现接口 [英] Explicitly marking derived class as implementing interface of base class

查看:23
本文介绍了显式地将派生类标记为基类的实现接口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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".

In this case output will be "Base".

如果我明确声明 Derived 实现了 IBase(它实际上已经由基类 Base 实现,而这样的注释似乎没有用),输出将是Derived"

If I explicitly state that Derived implements IBase (which is in fact already implemented by base class Base and such annotation seem to be useless) the output will be "Derived"

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

这种行为的原因是什么?

What's the reason for such behavior?

VS 15.3.5,C# 7

VS 15.3.5, C# 7

推荐答案

在 C# 5 规范的 13.4.4 到 13.4.6 节中进行了解释.下面引用了相关部分,但基本上,如果您明确声明一个类实现了一个接口,则会再次触发接口映射,因此编译器将 那个 类作为用来计算每个实现的类接口成员被映射到.

It's explained in sections 13.4.4 to 13.4.6 of the C# 5 specification. The relevant sections are quoted below, but basically if you explicitly state that a class implements an interface, that triggers interface mapping again, so the compiler takes that class as the one to use to work out which implementation each interface member is mapped to.

13.4.4 接口映射

类或结构必须提供在类或结构的基类列表中列出的所有接口成员的实现.在实现类或结构中定位接口成员的实现的过程称为接口映射.

A class or struct must provide implementations of all members of the interfaces that are listed in the base class list of the class or struct. The process of locating implementations of interface members in an implementing class or struct is known as interface mapping.

类或结构的接口映射 CC 的基类列表中指定的每个接口的每个成员定位一个实现.特定接口成员IM 的实现,其中I 是声明成员M 的接口,通过检查每个类或struct S,从 C 开始,对 C 的每个连续基类重复,直到找到匹配:

Interface mapping for a class or struct C locates an implementation for each member of each interface specified in the base class list of C. The implementation of a particular interface member I.M, where I is the interface in which the member M is declared, is determined by examining each class or struct S, starting with C and repeating for each successive base class of C, until a match is located:

  • 如果S包含匹配IM的显式接口成员实现的声明,那么这个成员就是IM.
  • 否则,如果S 包含与M 匹配的非静态公共成员的声明,则该成员是I.M 的实现.如果有多个成员匹配,则未指定哪个成员是 I.M 的实现.仅当 S 是一种构造类型时才会发生这种情况,其中泛型类型中声明的两个成员具有不同的签名,但类型参数使它们的签名相同.
  • If S contains a declaration of an explicit interface member implementation that matches I and M, then this member is the implementation of I.M.
  • Otherwise, if S contains a declaration of a non-static public member that matches M, then this member is the implementation of I.M. If more than one member matches, it is unspecified which member is the implementation of I.M. This situation can only occur if S is a constructed type where the two members as declared in the generic type have different signatures, but the type arguments make their signatures identical.

...

13.4.5 接口实现继承

一个类继承其基类提供的所有接口实现.如果不显式地重新实现接口,派生类就不能以任何方式改变它从基类继承的接口映射.例如,在声明中

A class inherits all interface implementations provided by its base classes. Without explicitly re-implementing an interface, a derived class cannot in any way alter the interface mappings it inherits from its base classes. For example, in the declarations

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

TextBox 中的 Paint 方法隐藏了 Control 中的 Paint 方法,但它没有改变Control.PaintIControl.Paint的映射,通过类实例和接口实例调用Paint将有以下效果

the Paint method in TextBox hides the Paint method in Control, but it does not alter the mapping of Control.Paint onto IControl.Paint, and calls to Paint through class instances and interface instances will have the following effects

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 接口重新实现

允许继承接口实现的类通过将其包含在基类列表中来重新实现接口.

A class that inherits an interface implementation is permitted to re-implement the interface by including it in the base class list.

接口的重新实现遵循与接口的初始实现完全相同的接口映射规则.因此,继承的接口映射对为重新实现接口而建立的接口映射没有任何影响.例如,在声明中

A re-implementation of an interface follows exactly the same interface mapping rules as an initial implementation of an interface. Thus, the inherited interface mapping has no effect whatsoever on the interface mapping established for the re-implementation of the interface. For example, in the declarations

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.

the fact that Control maps IControl.Paint onto Control.IControl.Paint doesn’t affect the re-implementation in MyControl, which maps IControl.Paint onto MyControl.Paint.

这篇关于显式地将派生类标记为基类的实现接口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆