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

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

问题描述

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

推荐答案

第13.4.4至13.4.6节对此进行了解释C#5规范。下面引用了相关的部分,但基本上如果你明确声明一个类实现了一个接口,那么它会再次触发接口映射,所以编译器将那个类作为用来计算每个实现的实现接口成员映射到。

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.

类或结构的接口映射 C C 的基类列表中指定的每个接口的每个成员定位一个实现。特定接口成员 IM 的实现,其中 I 是成员的接口声明M ,通过检查每个类或结构 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 包含一个显式接口成员实现的声明,该声明匹配 I M ,那么这个成员是 IM 的实现。

  • 否则,如果 S 包含与M匹配的非静态公共成员的声明,然后此成员是 IM 的实现。如果多个成员匹配,则未指定哪个成员是 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 的映射更改为 IControl.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() {}
}

事实那个控制 IControl.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天全站免登陆