默认接口方法default interface methods

  • [x] 建议[x] Proposed
  • [] 原型: 正在进行[ ] Prototype: In progress
  • [] 实现:无[ ] Implementation: None
  • [] 规范:正在进行,如下所示[ ] Specification: In progress, below

总结Summary

添加对 虚拟扩展方法 的支持-具有具体实现的接口中的方法。Add support for virtual extension methods - methods in interfaces with concrete implementations. 实现此类接口的类或结构需要具有接口方法的单个 特定 实现,该实现由类或结构实现,或从其基类或接口继承。A class or struct that implements such an interface is required to have a single most specific implementation for the interface method, either implemented by the class or struct, or inherited from its base classes or interfaces. 利用虚拟扩展方法,API 作者可以在未来版本中将方法添加到接口,而不会对该接口的现有实现中断源或二进制文件的兼容性。Virtual extension methods enable an API author to add methods to an interface in future versions without breaking source or binary compatibility with existing implementations of that interface.

它们类似于 Java 的 "默认方法"These are similar to Java's "Default Methods".

(根据可能的实现方法) 此功能需要 CLI/CLR 中的相应支持。(Based on the likely implementation technique) this feature requires corresponding support in the CLI/CLR. 利用此功能的程序不能在早期版本的平台上运行。Programs that take advantage of this feature cannot run on earlier versions of the platform.

动机Motivation

此功能的主要动机是The principal motivations for this feature are

详细设计Detailed design

接口的语法已扩展为允许The syntax for an interface is extended to permit

  • 声明常量、运算符、静态构造函数和嵌套类型的成员声明;member declarations that declare constants, operators, static constructors, and nested types;
  • 方法或索引器、属性或事件访问器的 正文 (即 "默认" 实现) ;a body for a method or indexer, property, or event accessor (that is, a "default" implementation);
  • 声明静态字段、方法、属性、索引器和事件的成员声明;member declarations that declare static fields, methods, properties, indexers, and events;
  • 使用显式接口实现语法的成员声明;与member declarations using the explicit interface implementation syntax; and
  • 显式访问修饰符(默认访问权限为 public)。Explicit access modifiers (the default access is public).

具有主体的成员允许接口为不提供重写实现的类和结构中的方法提供 "默认" 实现。Members with bodies permit the interface to provide a "default" implementation for the method in classes and structs that do not provide an overriding implementation.

接口不能包含实例状态。Interfaces may not contain instance state. 虽然现在允许使用静态字段,但接口中不允许使用实例字段。While static fields are now permitted, instance fields are not permitted in interfaces. 接口中不支持实例自动属性,因为它们将隐式声明隐藏的字段。Instance auto-properties are not supported in interfaces, as they would implicitly declare a hidden field.

静态方法和私有方法允许使用用于实现接口的公共 API 的代码的实用重构和组织。Static and private methods permit useful refactoring and organization of code used to implement the interface's public API.

接口中的方法重写必须使用显式接口实现语法。A method override in an interface must use the explicit interface implementation syntax.

在使用 variance_annotation 声明的类型形参的范围内声明类类型、结构类型或枚举类型是错误的。It is an error to declare a class type, struct type, or enum type within the scope of a type parameter that was declared with a variance_annotation. 例如,下面的声明 C 为错误。For example, the declaration of C below is an error.

interface IOuter<out T>
{
    class C { } // error: class declaration within the scope of variant type parameter 'T'
}

接口中的具体方法Concrete methods in interfaces

此功能的最简单形式是在接口中声明 具体方法 ,该方法是具有主体的方法。The simplest form of this feature is the ability to declare a concrete method in an interface, which is a method with a body.

interface IA
{
    void M() { WriteLine("IA.M"); }
}

实现此接口的类不需要实现其具体方法。A class that implements this interface need not implement its concrete method.

class C : IA { } // OK

IA i = new C();
i.M(); // prints "IA.M"

类中的最终重写 IA.M CM 中声明的具体方法 IAThe final override for IA.M in class C is the concrete method M declared in IA. 请注意,类不会从其接口继承成员;这不会被此功能更改:Note that a class does not inherit members from its interfaces; that is not changed by this feature:

new C().M(); // error: class 'C' does not contain a member 'M'

在接口的实例成员内, this 具有封闭接口的类型。Within an instance member of an interface, this has the type of the enclosing interface.

接口中的修饰符Modifiers in interfaces

接口的语法非常宽松,允许其成员具有修饰符。The syntax for an interface is relaxed to permit modifiers on its members. 允许以下项: privateprotectedinternalpublic 、、、、、 virtual abstract sealed static externpartialThe following are permitted: private, protected, internal, public, virtual, abstract, sealed, static, extern, and partial.

TODO:检查其他修饰符是否存在。TODO: check what other modifiers exist.

virtual除非 sealed 使用或修饰符,否则接口成员的声明包含主体 privateAn interface member whose declaration includes a body is a virtual member unless the sealed or private modifier is used. virtual修饰符可用于原本会隐式的函数成员 virtualThe virtual modifier may be used on a function member that would otherwise be implicitly virtual. 同样,尽管 abstract 是在没有主体的接口成员上的默认设置,但可以显式给定修饰符。Similarly, although abstract is the default on interface members without bodies, that modifier may be given explicitly. 可以使用关键字声明非虚拟成员 sealedA non-virtual member may be declared using the sealed keyword.

如果 private 接口的或函数成员没有正文,则是错误的 sealedIt is an error for a private or sealed function member of an interface to have no body. private函数成员不能具有修饰符 sealedA private function member may not have the modifier sealed.

访问修饰符可用于允许的所有种类成员的接口成员。Access modifiers may be used on interface members of all kinds of members that are permitted. 访问级别 public 为默认值,但它可以显式提供。The access level public is the default but it may be given explicitly.

打开问题: 我们需要指定访问修饰符(例如和)的精确含义 protected ,以及 internal 哪些声明在派生接口中 (并重写它们) 或在实现接口) 的类中实现 (它们。Open Issue: We need to specify the precise meaning of the access modifiers such as protected and internal, and which declarations do and do not override them (in a derived interface) or implement them (in a class that implements the interface).

接口可以声明 static 成员,包括嵌套类型、方法、索引器、属性、事件和静态构造函数。Interfaces may declare static members, including nested types, methods, indexers, properties, events, and static constructors. 所有接口成员的默认访问级别为 publicThe default access level for all interface members is public.

接口不能声明实例构造函数、析构函数或字段。Interfaces may not declare instance constructors, destructors, or fields.

*已关闭问题: _ 应允许在接口中声明运算符?*Closed Issue: _ Should operator declarations be permitted in an interface? 可能不是转换运算符,但其他运算符怎么样呢?Probably not conversion operators, but what about others? *决策*:允许运算符 except * 用于转换、相等和不等运算符。Decision_: Operators are permitted _except* for conversion, equality, and inequality operators.

*已关闭问题:new 允许在隐藏基接口成员的接口成员声明上使用 *Closed Issue: _ Should new be permitted on interface member declarations that hide members from base interfaces? 决策 *:是。_*Decision**: Yes.

*已关闭问题: _ 目前不允许 partial 使用某个接口或其成员。*Closed Issue: _ We do not currently permit partial on an interface or its members. 这需要单独建议。That would require a separate proposal. _ 决策 *:是。_*Decision**: Yes. https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-10-17.md#permit-partial-in-interface

接口中的替代Overrides in interfaces

重写声明 (例如,其中包含 override 修饰符的) 允许编程人员在编译器或运行时不会找到一个的接口中提供最具体的虚拟成员实现。Override declarations (i.e. those containing the override modifier) allow the programmer to provide a most specific implementation of a virtual member in an interface where the compiler or runtime would not otherwise find one. 它还允许将抽象成员从超级接口转换为派生接口中的默认成员。It also allows turning an abstract member from a super-interface into a default member in a derived interface. 允许重写声明通过使用接口名称(在这种情况下不允许使用访问修饰符 (不允许使用访问修饰符) 显式 重写特定基接口方法,) 。An override declaration is permitted to explicitly override a particular base interface method by qualifying the declaration with the interface name (no access modifier is permitted in this case). 不允许使用隐式重写。Implicit overrides are not permitted.

interface IA
{
    void M() { WriteLine("IA.M"); }
}
interface IB : IA
{
    override void IA.M() { WriteLine("IB.M"); } // explicitly named
}
interface IC : IA
{
    override void M() { WriteLine("IC.M"); } // implicitly named
}

接口中的重写声明不能声明 sealedOverride declarations in interfaces may not be declared sealed.

接口中的公共 virtual 函数成员可在派生接口中显式重写, (方法是在重写声明中用最初声明方法的接口类型限定名称,并省略访问修饰符) 。Public virtual function members in an interface may be overridden in a derived interface explicitly (by qualifying the name in the override declaration with the interface type that originally declared the method, and omitting an access modifier).

virtual 接口中的函数成员只能显式重写 (在派生接口中不隐式) ,而不能 public 显式在类或结构中实现的成员 (隐式) 。virtual function members in an interface may only be overridden explicitly (not implicitly) in derived interfaces, and members that are not public may only be implemented in a class or struct explicitly (not implicitly). 在任一情况下,重写或实现的成员都必须可在重写时 访问In either case, the overridden or implemented member must be accessible where it is overridden.

ReabstractionReabstraction

在接口中声明的虚拟 (具体) 方法可能会被重写为在派生接口中是抽象的A virtual (concrete) method declared in an interface may be overridden to be abstract in a derived interface

interface IA
{
    void M() { WriteLine("IA.M"); }
}
interface IB : IA
{
    abstract void IA.M();
}
class C : IB { } // error: class 'C' does not implement 'IA.M'.

abstract (的声明中不需要修饰符, IB.M 这是接口) 中的默认值,但最好是在重写声明中显式。The abstract modifier is not required in the declaration of IB.M (that is the default in interfaces), but it is probably good practice to be explicit in an override declaration.

这适用于方法的默认实现不恰当并且应通过实现类提供更合适的实现的派生接口。This is useful in derived interfaces where the default implementation of a method is inappropriate and a more appropriate implementation should be provided by implementing classes.

打开问题: 是否应允许 reabstraction?Open Issue: Should reabstraction be permitted?

最特定的替代规则The most specific override rule

我们要求每个接口和类在类型或其直接和间接接口中出现的重写中的每个虚拟成员都有一个 最特定的重写We require that every interface and class have a most specific override for every virtual member among the overrides appearing in the type or its direct and indirect interfaces. 最具体的替代 是比每个其他重写更具体的替代。The most specific override is a unique override that is more specific than every other override. 如果没有替代,则将成员本身视为最特定的重写。If there is no override, the member itself is considered the most specific override.

M1 M2 如果 M1 在类型上声明,则将一个重写视为比另一个重写更具体,在 T1 M2 类型上声明,在类型上声明 T2 ;One override M1 is considered more specific than another override M2 if M1 is declared on type T1, M2 is declared on type T2, and either

  1. T1 包含 T2 在其直接或间接接口中,或T1 contains T2 among its direct or indirect interfaces, or
  2. T2 是一个接口类型,但 T1 它不是接口类型。T2 is an interface type but T1 is not an interface type.

例如:For example:

interface IA
{
    void M() { WriteLine("IA.M"); }
}
interface IB : IA
{
    void IA.M() { WriteLine("IB.M"); }
}
interface IC : IA
{
    void IA.M() { WriteLine("IC.M"); }
}
interface ID : IB, IC { } // error: no most specific override for 'IA.M'
abstract class C : IB, IC { } // error: no most specific override for 'IA.M'
abstract class D : IA, IB, IC // ok
{
    public abstract void M();
}

最具体的替代规则可确保冲突 (即,由菱形继承引起的歧义) 程序员在发生冲突的情况下显式解决该问题。The most specific override rule ensures that a conflict (i.e. an ambiguity arising from diamond inheritance) is resolved explicitly by the programmer at the point where the conflict arises.

由于我们在接口中支持显式抽象替代,因此也可以在类中执行此操作Because we support explicit abstract overrides in interfaces, we could do so in classes as well

abstract class E : IA, IB, IC // ok
{
    abstract void IA.M();
}

打开问题:我们是否应在类中支持显式接口抽象替代?Open issue: should we support explicit interface abstract overrides in classes?

此外,如果在类声明中,某些接口方法的最特定重写是在接口中声明的抽象重写,则是错误的。In addition, it is an error if in a class declaration the most specific override of some interface method is an abstract override that was declared in an interface. 这是生效首先使用新术语的现有规则。This is an existing rule restated using the new terminology.

interface IF
{
    void M();
}
abstract class F : IF { } // error: 'F' does not implement 'IF.M'

在接口中声明的虚拟属性有可能在一个接口中具有最特定的重写 get ,并且在不同的接口中对其访问器使用最特定的重写 setIt is possible for a virtual property declared in an interface to have a most specific override for its get accessor in one interface and a most specific override for its set accessor in a different interface. 这被视为违反 最具体的替代 规则。This is considered a violation of the most specific override rule.

staticprivate 方法static and private methods

由于接口现在可以包含可执行代码,因此将常见代码抽象到私有和静态方法非常有用。Because interfaces may now contain executable code, it is useful to abstract common code into private and static methods. 现在,我们在接口中允许这些。We now permit these in interfaces.

*已关闭问题 :我们是否应支持私有方法?*Closed issue : Should we support private methods? 是否应支持静态方法?Should we support static methods? 决定:是* Decision: YES*

打开问题:是否应允许接口方法为 protectedinternal 或其他访问?Open issue: should we permit interface methods to be protected or internal or other access? 如果是,语义是什么?If so, what are the semantics? 它们是否 virtual 默认为?Are they virtual by default? 如果是,有没有办法使它们成为非虚拟的?If so, is there a way to make them non-virtual?

打开问题:如果支持静态方法,是否应支持 (静态) 运算符?Open issue: If we support static methods, should we support (static) operators?

基接口调用Base interface invocations

使用默认方法从接口派生的类型中的代码可以显式调用该接口的 "base" 实现。Code in a type that derives from an interface with a default method can explicitly invoke that interface's "base" implementation.

interface I0
{
   void M() { Console.WriteLine("I0"); }
}
interface I1 : I0
{
   override void M() { Console.WriteLine("I1"); }
}
interface I2 : I0
{
   override void M() { Console.WriteLine("I2"); }
}
interface I3 : I1, I2
{
   // an explicit override that invoke's a base interface's default method
   void I0.M() { I2.base.M(); }
}

(非静态) 方法的实例允许通过使用语法对其命名来在直接基接口 nonvirtually 中调用可访问实例方法的实现 base(Type).MAn instance (nonstatic) method is permitted to invoke the implementation of an accessible instance method in a direct base interface nonvirtually by naming it using the syntax base(Type).M. 此方法在以下情况下很有用:通过委托给某个特定基实现来解析由于菱形继承而需要提供的重写。This is useful when an override that is required to be provided due to diamond inheritance is resolved by delegating to one particular base implementation.

interface IA
{
    void M() { WriteLine("IA.M"); }
}
interface IB : IA
{
    override void IA.M() { WriteLine("IB.M"); }
}
interface IC : IA
{
    override void IA.M() { WriteLine("IC.M"); }
}

class D : IA, IB, IC
{
    void IA.M() { base(IB).M(); }
}

virtual abstract 使用语法访问或成员时 base(Type).M ,需要 Type 包含的唯一的唯一 重写 MWhen a virtual or abstract member is accessed using the syntax base(Type).M, it is required that Type contains a unique most specific override for M.

绑定基子句Binding base clauses

接口现在包含类型。Interfaces now contain types. 这些类型可以在基子句中用作基接口。These types may be used in the base clause as base interfaces. 绑定基子句时,可能需要知道绑定这些类型的基接口集 (例如,要在这些类型中查找和解析受保护的访问) 。When binding a base clause, we may need to know the set of base interfaces to bind those types (e.g. to lookup in them and to resolve protected access). 因此,会循环定义接口的基子句的含义。The meaning of an interface's base clause is thus circularly defined. 为了打破循环,我们添加了与类中已有的类似规则相对应的新语言规则。To break the cycle, we add a new language rules corresponding to a similar rule already in place for classes.

在确定接口的 interface_base 含义时,将暂时假设基接口为空。While determining the meaning of the interface_base of an interface, the base interfaces are temporarily assumed to be empty. 这可以确保基本子句的含义无法以递归方式依赖于自身。Intuitively this ensures that the meaning of a base clause cannot recursively depend on itself.

我们使用以下规则:We used to have the following rules:

"当类 B 从类 A 派生时,它是依赖于 B 的编译时错误。类 直接依赖于 其直接基类 (如果任何) 并且 直接依赖于该类,则在任何) 时,该类会立即嵌套 (。"When a class B derives from a class A, it is a compile-time error for A to depend on B. A class directly depends on its direct base class (if any) and directly depends on the class within which it is immediately nested (if any). 根据此定义,类所依赖的完整 集是 直接依赖 关系的反身和可传递闭包。Given this definition, the complete set of classes upon which a class depends is the reflexive and transitive closure of the directly depends on relationship."

接口直接或间接从自身继承时,会发生编译时错误。It is a compile-time error for an interface to directly or indirectly inherit from itself. 接口的 基接口 是显式基接口及其基接口。The base interfaces of an interface are the explicit base interfaces and their base interfaces. 换言之,基接口集是显式基接口的完全可传递的闭包、其显式基接口等。In other words, the set of base interfaces is the complete transitive closure of the explicit base interfaces, their explicit base interfaces, and so on.

我们将调整它们,如下所示:We are adjusting them as follows:

当类 B 从类 A 派生时,它是依赖于 B 的编译时错误。类 直接依赖于 它的直接基类 (如果任何) 并且 直接依赖于 在任何) (立即嵌套的 类型When a class B derives from a class A, it is a compile-time error for A to depend on B. A class directly depends on its direct base class (if any) and directly depends on the type within which it is immediately nested (if any).

接口 IB 扩展接口 IA 时,IA 依赖于 IB 会出现编译时错误。When an interface IB extends an interface IA, it is a compile-time error for IA to depend on IB. 接口 直接依赖于 它的直接基接口, (如果任何) 并且 直接依赖于 在任何) (立即嵌套的类型。An interface directly depends on its direct base interfaces (if any) and directly depends on the type within which it is immediately nested (if any).

考虑到这些定义,类型所依赖的完整 类型 集是 直接依赖 关系的反身和可传递闭包。Given these definitions, the complete set of types upon which a type depends is the reflexive and transitive closure of the directly depends on relationship.

对现有程序的影响Effect on existing programs

此处介绍的规则不会影响现有程序的含义。The rules presented here are intended to have no effect on the meaning of existing programs.

示例 1:Example 1:

interface IA
{
    void M();
}
class C: IA // Error: IA.M has no concrete most specific override in C
{
    public static void M() { } // method unrelated to 'IA.M' because static
}

示例 2:Example 2:

interface IA
{
    void M();
}
class Base: IA
{
    void IA.M() { }
}
class Derived: Base, IA // OK, all interface members have a concrete most specific override
{
    private void M() { } // method unrelated to 'IA.M' because private
}

对于涉及默认接口方法的类似情况,相同的规则将产生类似的结果:The same rules give similar results to the analogous situation involving default interface methods:

interface IA
{
    void M() { }
}
class Derived: IA // OK, all interface members have a concrete most specific override
{
    private void M() { } // method unrelated to 'IA.M' because private
}

*已关闭问题 :确认这是规范的预期结果。*Closed issue : confirm that this is an intended consequence of the specification. 决定:是* Decision: YES*

运行时方法解析Runtime method resolution

已关闭问题: 规范应描述接口默认方法的运行时方法解析算法。Closed Issue: The spec should describe the runtime method resolution algorithm in the face of interface default methods. 我们需要确保语义与语言语义一致,例如,已声明的方法执行和不重写或实现 internal 方法。We need to ensure that the semantics are consistent with the language semantics, e.g. which declared methods do and do not override or implement an internal method.

CLR 支持 APICLR support API

为了使编译器能够在为支持此功能的运行时进行检测,将修改此类运行时的库,以便通过中讨论的 API 来公布这一事实 https://github.com/dotnet/corefx/issues/17116In order for compilers to detect when they are compiling for a runtime that supports this feature, libraries for such runtimes are modified to advertise that fact through the API discussed in https://github.com/dotnet/corefx/issues/17116. 我们添加We add

namespace System.Runtime.CompilerServices
{
    public static class RuntimeFeature
    {
        // Presence of the field indicates runtime support
        public const string DefaultInterfaceImplementation = nameof(DefaultInterfaceImplementation);
    }
}

*打开问题 _: _CLR * 功能的最佳名称吗?Open issue _: Is that the best name for the _CLR feature? CLR 功能不仅仅 (例如放宽保护约束、支持接口中的重写等) 。The CLR feature does much more than just that (e.g. relaxes protection constraints, supports overrides in interfaces, etc). 它可能称为 "接口中的具体方法" 或 "特征" 之类的内容?Perhaps it should be called something like "concrete methods in interfaces", or "traits"?

要指定的其他区域Further areas to be specified

  • [] 通过向现有接口添加默认的接口方法和替代,对导致源和二进制兼容性的各种影响进行编目是非常有用的。[ ] It would be useful to catalog the kinds of source and binary compatibility effects caused by adding default interface methods and overrides to existing interfaces.

缺点Drawbacks

此建议需要对 CLR 规范 (进行协调更新,以支持接口和方法解析) 中的具体方法。This proposal requires a coordinated update to the CLR specification (to support concrete methods in interfaces and method resolution). 因此,这种情况相当 "昂贵",可能需要将其与其他可能需要 CLR 更改的功能结合在一起。It is therefore fairly "expensive" and it may be worth doing in combination with other features that we also anticipate would require CLR changes.

备选方法Alternatives

无。None.

未解决的问题Unresolved questions

  • 在上面的方案中,我们提出了开放式问题。Open questions are called out throughout the proposal, above.
  • 另请参阅 https://github.com/dotnet/csharplang/issues/406 以获取开放问题的列表。See also https://github.com/dotnet/csharplang/issues/406 for a list of open questions.
  • 详细规范必须描述运行时用于选择要调用的精确方法的解析机制。The detailed specification must describe the resolution mechanism used at runtime to select the precise method to be invoked.
  • 新编译器所生成的元数据与旧编译器使用的元数据交互需要进行详细处理。The interaction of metadata produced by new compilers and consumed by older compilers needs to be worked out in detail. 例如,我们需要确保使用的元数据表示形式不会导致接口中添加默认实现,以在由较旧的编译器编译时破坏实现该接口的现有类。For example, we need to ensure that the metadata representation that we use does not cause the addition of a default implementation in an interface to break an existing class that implements that interface when compiled by an older compiler. 这可能会影响可使用的元数据表示形式。This may affect the metadata representation that we can use.
  • 设计必须考虑与其他语言的互操作性和其他语言的现有编译器。The design must consider interoperation with other languages and existing compilers for other languages.

解决的问题Resolved Questions

Abstract 重写Abstract Override

早期草案规范包含了 "reabstract" 继承方法的能力:The earlier draft spec contained the ability to "reabstract" an inherited method:

interface IA
{
    void M();
}
interface IB : IA
{
    override void M() { }
}
interface IC : IB
{
    override void M(); // make it abstract again
}

我的说明2017-03-20 显示我们决定不允许这样做。My notes for 2017-03-20 showed that we decided not to allow this. 但是,其中至少有两个用例:However, there are at least two use cases for it:

  1. Java Api,此功能的某些用户希望进行互操作,这取决于此功能。The Java APIs, with which some users of this feature hope to interoperate, depend on this facility.
  2. 利用这 一优势来 编程。Programming with traits benefits from this. Reabstraction 是 "特征" 语言功能 (的元素之一 https://en.wikipedia.org/wiki/Trait_(computer_programming)) 。Reabstraction is one of the elements of the "traits" language feature (https://en.wikipedia.org/wiki/Trait_(computer_programming)). 以下类允许使用类:The following is permitted with classes:
public abstract class Base
{
    public abstract void M();
}
public abstract class A : Base
{
    public override void M() { }
}
public abstract class B : A
{
    public override abstract void M(); // reabstract Base.M
}

遗憾的是,此代码不能作为一组接口 (特征) ,除非允许这样做。Unfortunately this code cannot be refactored as a set of interfaces (traits) unless this is permitted. 贪婪的 Jared 原则 应允许这样做。By the Jared principle of greed, it should be permitted.

已关闭问题: 是否应允许 reabstraction?Closed issue: Should reabstraction be permitted? [我的笔记出错了。[YES] My notes were wrong. LDM 说明指出接口中允许 reabstraction。The LDM notes say that reabstraction is permitted in an interface. 不在类中。Not in a class.

虚拟修饰符与密封修饰符Virtual Modifier vs Sealed Modifier

From Aleksey TsingauzFrom Aleksey Tsingauz:

我们决定允许在接口成员上显式声明修饰符,除非有理由禁止这样做。We decided to allow modifiers explicitly stated on interface members, unless there is a reason to disallow some of them. 这就为虚拟修饰符带来了一个有趣的问题。This brings an interesting question around virtual modifier. 是否应在具有默认实现的成员上需要?Should it be required on members with default implementation?

我们可能会说:We could say that:

  • 如果没有任何实现,也没有指定虚拟和密封,则假定该成员是抽象成员。if there is no implementation and neither virtual, nor sealed are specified, we assume the member is abstract.
  • 如果有一个实现并且未指定任何抽象和密封,则假定该成员是虚拟的。if there is an implementation and neither abstract, nor sealed are specified, we assume the member is virtual.
  • 要使方法既不是虚拟的也不是抽象的,必须使用 sealed 修饰符。sealed modifier is required to make a method neither virtual, nor abstract.

另外,我们也可能会说虚拟修饰符对于虚拟成员是必需的。Alternatively, we could say that virtual modifier is required for a virtual member. 例如,如果存在未使用虚拟修饰符显式标记的实现的成员,则它既不是虚拟的也不是抽象的。I.e, if there is a member with implementation not explicitly marked with virtual modifier, it is neither virtual, nor abstract. 当方法从类移到接口时,此方法可能会提供更好的体验:This approach might provide better experience when a method is moved from a class to an interface:

  • 抽象方法保持抽象。an abstract method stays abstract.
  • 虚方法保持为虚方法。a virtual method stays virtual.
  • 没有任何修饰符的方法将保持不变,也不会成为抽象方法。a method without any modifier stays neither virtual, nor abstract.
  • 密封修饰符不能应用于不是重写的方法。sealed modifier cannot be applied to a method that is not an override.

你有什么看法?What do you think?

已关闭问题: 是否应隐式地 (实现) 的具体方法 virtualClosed Issue: Should a concrete method (with implementation) be implicitly virtual? [[YES]

决策: 在 LDM 2017-04-05 中创建:Decisions: Made in the LDM 2017-04-05:

  1. 非虚拟应通过或显式表达 sealed privatenon-virtual should be explicitly expressed through sealed or private.
  2. sealed 用于使接口实例成员具有非虚拟主体的关键字sealed is the keyword to make interface instance members with bodies non-virtual
  3. 我们希望允许接口中的所有修饰符We want to allow all modifiers in interfaces
  4. 接口成员的默认可访问性是公共的,其中包括嵌套类型Default accessibility for interface members is public, including nested types
  5. 接口中的私有函数成员是隐式密封的, sealed 不允许在这些成员上使用。private function members in interfaces are implicitly sealed, and sealed is not permitted on them.
  6. 接口) (的私有类是允许的,可以密封,这意味着密封在密封类的类中。Private classes (in interfaces) are permitted and can be sealed, and that means sealed in the class sense of sealed.
  7. 缺少良好的建议,不允许在接口或其成员上使用 partial。Absent a good proposal, partial is still not allowed on interfaces or their members.

二进制兼容性1Binary Compatibility 1

当库提供默认实现时When a library provides a default implementation

interface I1
{
    void M() { Impl1 }
}
interface I2 : I1
{
}
class C : I2
{
}

我们了解中的实现 I1.M CI1.MWe understand that the implementation of I1.M in C is I1.M. 如果包含的程序集 I2 按如下方式更改并重新编译,会发生什么情况What if the assembly containing I2 is changed as follows and recompiled

interface I2 : I1
{
    override void M() { Impl2 }
}

C 不会重新编译。but C is not recompiled. 程序运行时会发生什么情况?What happens when the program is run? 调用 (C as I1).M()An invocation of (C as I1).M()

  1. I1.MRuns I1.M
  2. I2.MRuns I2.M
  3. 引发某种类型的运行时错误Throws some kind of runtime error

决策: 进行2017-04-11:运行 I2.M ,这是运行时明确的最具体的重写。Decision: Made 2017-04-11: Runs I2.M, which is the unambiguously most specific override at runtime.

事件访问器 (关闭) Event accessors (closed)

已关闭问题: 事件是否可以重写 "分段"?Closed Issue: Can an event be overridden "piecewise"?

请考虑这种情况:Consider this case:

public interface I1
{
    event T e1;
}
public interface I2 : I1
{
    override event T
    {
        add { }
        // error: "remove" accessor missing
    }
}

不允许使用事件的 "部分" 实现,因为在类中,事件声明的语法不允许只有一个访问器;必须同时提供 (或都不) 。This "partial" implementation of the event is not permitted because, as in a class, the syntax for an event declaration does not permit only one accessor; both (or neither) must be provided. 通过允许语法中的 abstract remove 访问器在缺少正文时隐式抽象,可以实现相同的目的:You could accomplish the same thing by permitting the abstract remove accessor in the syntax to be implicitly abstract by the absence of a body:

public interface I1
{
    event T e1;
}
public interface I2 : I1
{
    override event T
    {
        add { }
        remove; // implicitly abstract
    }
}

请注意, 这是一个新的 (建议) 语法Note that this is a new (proposed) syntax. 在当前语法中,事件访问器具有强制正文。In the current grammar, event accessors have a mandatory body.

已关闭问题: 事件访问器是否可以通过省略主体 (隐式) 抽象,类似于通过省略体 (隐式) 抽象的接口和属性访问器中的方法。Closed Issue: Can an event accessor be (implicitly) abstract by the omission of a body, similarly to the way that methods in interfaces and property accessors are (implicitly) abstract by the omission of a body?

决策: (2017-04-18) 否,事件声明需要两个具体访问器 (或都不) 。Decision: (2017-04-18) No, event declarations require both concrete accessors (or neither).

(关闭) 类中的 ReabstractionReabstraction in a Class (closed)

已关闭问题: 应确认允许这样做 (否则,添加默认实现将是重大更改) :Closed Issue: We should confirm that this is permitted (otherwise adding a default implementation would be a breaking change):

interface I1
{
    void M() { }
}
abstract class C : I1
{
    public abstract void M(); // implement I1.M with an abstract method in C
}

决策: (2017-04-18) 是,将主体添加到接口成员声明不应中断 C。Decision: (2017-04-18) Yes, adding a body to an interface member declaration shouldn't break C.

密封的替代 (关闭) Sealed Override (closed)

前面的问题隐式假定 sealed 修饰符可以应用于 override 接口中的。The previous question implicitly assumes that the sealed modifier can be applied to an override in an interface. 这与草案规范相抵触。This contradicts the draft specification. 是否允许密封替代?Do we want to permit sealing an override? 应考虑密封的源和二进制兼容性影响。Source and binary compatibility effects of sealing should be considered.

已关闭问题: 是否应允许密封替代?Closed Issue: Should we permit sealing an override?

决策: (2017-04-18) 不允许 sealed 在接口中使用替代。Decision: (2017-04-18) Let's not allowed sealed on overrides in interfaces. 接口成员的唯一使用 sealed 是在其初始声明中使其成为非虚拟的。The only use of sealed on interface members is to make them non-virtual in their initial declaration.

菱形继承和类 (关闭) Diamond inheritance and classes (closed)

提议的草稿在菱形继承方案中,类优先于接口替代:The draft of the proposal prefers class overrides to interface overrides in diamond inheritance scenarios:

我们要求每个接口和类在类型或其直接和间接接口中出现的重写中都有对每个接口方法的 最特定的重写We require that every interface and class have a most specific override for every interface method among the overrides appearing in the type or its direct and indirect interfaces. 最具体的替代 是比每个其他重写更具体的替代。The most specific override is a unique override that is more specific than every other override. 如果没有替代,则将方法本身视为最特定的重写。If there is no override, the method itself is considered the most specific override.

M1 M2 如果 M1 在类型上声明,则将一个重写视为比另一个重写更具体,在 T1 M2 类型上声明,在类型上声明 T2 ;One override M1 is considered more specific than another override M2 if M1 is declared on type T1, M2 is declared on type T2, and either

  1. T1 包含 T2 在其直接或间接接口中,或T1 contains T2 among its direct or indirect interfaces, or
  2. T2 是一个接口类型,但 T1 它不是接口类型。T2 is an interface type but T1 is not an interface type.

此方案是The scenario is this

interface IA
{
    void M();
}
interface IB : IA
{
    override void M() { WriteLine("IB"); }
}
class Base : IA
{
    void IA.M() { WriteLine("Base"); }
}
class Derived : Base, IB // allowed?
{
    static void Main()
    {
        Ia a = new Derived();
        a.M();           // what does it do?
    }
}

应确认此行为 (或确定) We should confirm this behavior (or decide otherwise)

*已关闭问题: _ 确认 _most 特定的替代 * 适用于混合类和接口 (类在类与接口) 的优先级。Closed Issue: _ Confirm the draft spec, above, for _most specific override as it applies to mixed classes and interfaces (a class takes priority over an interface). 请参阅 https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-04-19.md#diamonds-with-classesSee https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-04-19.md#diamonds-with-classes.

接口方法 vs 结构 (关闭) Interface methods vs structs (closed)

默认的接口方法和结构之间存在一些不幸的交互。There are some unfortunate interactions between default interface methods and structs.

interface IA
{
    public void M() { }
}
struct S : IA
{
}

请注意,不会继承接口成员:Note that interface members are not inherited:

var s = default(S);
s.M(); // error: 'S' does not contain a member 'M'

因此,客户端必须对该结构进行方框才能调用接口方法Consequently, the client must box the struct to invoke interface methods

IA s = default(S); // an S, boxed
s.M(); // ok

采用这种方式进行装箱将违背类型的主要优点 structBoxing in this way defeats the principal benefits of a struct type. 而且,任何变化方法都不会有明显的影响,因为它们在结构的已 装箱副本 上操作:Moreover, any mutation methods will have no apparent effect, because they are operating on a boxed copy of the struct:

interface IB
{
    public void Increment() { P += 1; }
    public int P { get; set; }
}
struct T : IB
{
    public int P { get; set; } // auto-property
}

T t = default(T);
Console.WriteLine(t.P); // prints 0
(t as IB).Increment();
Console.WriteLine(t.P); // prints 0

已关闭问题: 我们可以对此做些什么:Closed Issue: What can we do about this:

  1. 禁止 struct 继承默认实现。Forbid a struct from inheriting a default implementation. 所有接口方法将在中被视为抽象方法 structAll interface methods would be treated as abstract in a struct. 稍后,我们可能需要花费一段时间来决定如何使其更好地工作。Then we may take time later to decide how to make it work better.
  2. 提供了一种可避免装箱的代码生成策略。Come up with some kind of code generation strategy that avoids boxing. 在类似的方法中 IB.Increment ,的类型 this 可能类似于约束为的类型参数 IBInside a method like IB.Increment, the type of this would perhaps be akin to a type parameter constrained to IB. 与此相结合,若要避免调用方中的装箱,将从接口继承非抽象方法。In conjunction with that, to avoid boxing in the caller, non-abstract methods would be inherited from interfaces. 这会显著提高编译器和 CLR 实现的工作效果。This may increase compiler and CLR implementation work substantially.
  3. 不用担心,只是将其保留为 wart。Not worry about it and just leave it as a wart.
  4. 其他想法?Other ideas?

决策: 不用担心,只是将其保留为 wart。Decision: Not worry about it and just leave it as a wart. 请参阅 https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-04-19.md#structs-and-default-implementationsSee https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-04-19.md#structs-and-default-implementations.

基接口调用 (关闭) Base interface invocations (closed)

草案规范建议使用 Java 提供的基接口调用的语法: Interface.base.M()The draft spec suggests a syntax for base interface invocations inspired by Java: Interface.base.M(). 我们需要至少为初始原型选择一种语法。We need to select a syntax, at least for the initial prototype. 我喜欢 base<Interface>.M()My favorite is base<Interface>.M().

已关闭问题: 基本成员调用的语法是什么?Closed Issue: What is the syntax for a base member invocation?

决策: 语法为 base(Interface).M()Decision: The syntax is base(Interface).M(). 请参阅 https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-04-19.md#base-invocationSee https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-04-19.md#base-invocation. 接口如此命名必须是基接口,但不需要是直接基接口。The interface so named must be a base interface, but does not need to be a direct base interface.

打开问题: 是否应允许在类成员中调用基接口?Open Issue: Should base interface invocations be permitted in class members?

决策:是。Decision: Yes. https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-04-19.md#base-invocation

(关闭重写非公共接口成员) Overriding non-public interface members (closed)

在接口中,使用修饰符重写基接口中的非公共成员 overrideIn an interface, non-public members from base interfaces are overridden using the override modifier. 如果它是命名包含成员的接口的 "显式" 重写,则省略访问修饰符。If it is an "explicit" override that names the interface containing the member, the access modifier is omitted.

已关闭问题: 如果它是一个不命名接口的 "隐式" 重写,则访问修饰符是否必须匹配?Closed Issue: If it is an "implicit" override that does not name the interface, does the access modifier have to match?

决策: 仅公共成员可以隐式重写,并且访问必须匹配。Decision: Only public members may be implicitly overridden, and the access must match. 请参阅 https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-04-18.md#dim-implementing-a-non-public-interface-member-not-in-listSee https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-04-18.md#dim-implementing-a-non-public-interface-member-not-in-list.

打开问题: 访问修饰符是必需的还是可选的,或在显式重写(如)上省略 override void IB.M() {}Open Issue: Is the access modifier required, optional, or omitted on an explicit override such as override void IB.M() {}?

打开问题:override在显式重写(如)上是必需的、可选的或省略的 void IB.M() {}Open Issue: Is override required, optional, or omitted on an explicit override such as void IB.M() {}?

如何实现类中的非公共接口成员?How does one implement a non-public interface member in a class? 这可能是必须显式完成的吗?Perhaps it must be done explicitly?

interface IA
{
    internal void MI();
    protected void MP();
}
class C : IA
{
    // are these implementations?
    internal void MI() {}
    protected void MP() {}
}

已关闭问题: 如何实现类中的非公共接口成员?Closed Issue: How does one implement a non-public interface member in a class?

决策: 您只能显式实现非公共接口成员。Decision: You can only implement non-public interface members explicitly. 请参阅 https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-04-18.md#dim-implementing-a-non-public-interface-member-not-in-listSee https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-04-18.md#dim-implementing-a-non-public-interface-member-not-in-list.

决策:不 override 允许在接口成员上使用关键字。Decision: No override keyword permitted on interface members. https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-10-17.md#does-an-override-in-an-interface-introduce-a-new-member

二进制兼容性 2 (关闭) Binary Compatibility 2 (closed)

请考虑以下代码,其中每个类型都在单独的程序集中Consider the following code in which each type is in a separate assembly

interface I1
{
    void M() { Impl1 }
}
interface I2 : I1
{
    override void M() { Impl2 }
}
interface I3 : I1
{
}
class C : I2, I3
{
}

我们了解中的实现 I1.M CI2.MWe understand that the implementation of I1.M in C is I2.M. 如果包含的程序集 I3 按如下方式更改并重新编译,会发生什么情况What if the assembly containing I3 is changed as follows and recompiled

interface I3 : I1
{
    override void M() { Impl3 }
}

C 不会重新编译。but C is not recompiled. 程序运行时会发生什么情况?What happens when the program is run? 调用 (C as I1).M()An invocation of (C as I1).M()

  1. I1.MRuns I1.M
  2. I2.MRuns I2.M
  3. I3.MRuns I3.M
  4. 2或3,确定性Either 2 or 3, deterministically
  5. 引发某种类型的运行时异常Throws some kind of runtime exception

决策:在 5) (引发异常。Decision: Throw an exception (5). 请参阅 https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-10-17.md#issues-in-default-interface-methodsSee https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-10-17.md#issues-in-default-interface-methods.

是否允许 partial 接口?Permit partial in interface? (关闭) (closed)

如果接口的使用方式类似于使用抽象类的方式,则声明这些接口可能会很有用 partialGiven that interfaces may be used in ways analogous to the way abstract classes are used, it may be useful to declare them partial. 这对于生成器而言特别有用。This would be particularly useful in the face of generators.

建议: 删除接口和接口的成员不能声明的语言限制 partialProposal: Remove the language restriction that interfaces and members of interfaces may not be declared partial.

决策:是。Decision: Yes. 请参阅 https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-10-17.md#permit-partial-in-interfaceSee https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-10-17.md#permit-partial-in-interface.

Main 在接口中?Main in an interface? (关闭) (closed)

打开问题:static Main接口中的方法是否是程序入口点的候选项?Open Issue: Is a static Main method in an interface a candidate to be the program's entry point?

决策:是。Decision: Yes. 请参阅 https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-10-17.md#main-in-an-interfaceSee https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-10-17.md#main-in-an-interface.

确认 (关闭) 的公共非虚拟方法的意图Confirm intent to support public non-virtual methods (closed)

我们是否可以确认 (或反向) 我们决定是否允许接口中的非虚拟公共方法?Can we please confirm (or reverse) our decision to permit non-virtual public methods in an interface?

interface IA
{
    public sealed void M() { }
}

半闭问题: (2017-04-18) 我们认为它将有用,但会返回到它。Semi-Closed Issue: (2017-04-18) We think it is going to be useful, but will come back to it. 这是一种精神模型的工作块。This is a mental model tripping block.

决策:是。Decision: Yes. https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-10-17.md#confirm-that-we-support-public-non-virtual-methods.https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-10-17.md#confirm-that-we-support-public-non-virtual-methods.

override接口中的是否引入了新成员?Does an override in an interface introduce a new member? (关闭) (closed)

有几种方法可以观察重写声明是否引入了新成员。There are a few ways to observe whether an override declaration introduces a new member or not.

interface IA
{
    void M(int x) { }
}
interface IB : IA
{
    override void M(int y) { }
}
interface IC : IB
{
    static void M2()
    {
        M(y: 3); // permitted?
    }
    override void IB.M(int z) { } // permitted? What does it override?
}

打开问题: 接口中的重写声明是否引入了新成员?Open Issue: Does an override declaration in an interface introduce a new member? (关闭) (closed)

在类中,重写方法在某种方式上为 "visible"。In a class, an overriding method is "visible" in some senses. 例如,其参数的名称优先于重写方法中的参数的名称。For example, the names of its parameters take precedence over the names of parameters in the overridden method. 可以在接口中重复该行为,因为始终存在最特定的重写。It may be possible to duplicate that behavior in interfaces, as there is always a most specific override. 但我们想要复制该行为吗?But do we want to duplicate that behavior?

此外,还可以 "重写" 重写方法呢?Also, it is possible to "override" an override method? 差异[Moot]

决策:不 override 允许在接口成员上使用关键字。Decision: No override keyword permitted on interface members. https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-10-17.md#does-an-override-in-an-interface-introduce-a-new-member.https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-10-17.md#does-an-override-in-an-interface-introduce-a-new-member.

具有专用访问器的属性 (关闭) Properties with a private accessor (closed)

我们说,private 成员不是虚拟的,不允许结合虚拟和私有。We say that private members are not virtual, and the combination of virtual and private is disallowed. 但对于具有专用访问器的属性怎么办呢?But what about a property with a private accessor?

interface IA
{
    public virtual int P
    {
        get => 3;
        private set => { }
    }
}

是否允许这样做?Is this allowed? set访问器是否在此处 virtualIs the set accessor here virtual or not? 它可以在可访问的位置重写吗?Can it be overridden where it is accessible? 下面是否隐式仅实现 get 访问器?Does the following implicitly implement only the get accessor?

class C : IA
{
    public int P
    {
        get => 4;
        set { }
    }
}

由于 IA,以下原因可能会导致错误。设置不是虚拟的,也可能是因为它无法访问?Is the following presumably an error because IA.P.set isn't virtual and also because it isn't accessible?

class C : IA
{
    int IA.P
    {
        get => 4;
        set { }
    }
}

决策:第一个示例看起来有效,而最后一个示例则无效。Decision: The first example looks valid, while the last does not. 这会类似解析为 c # 中的工作方式。This is resolved analogously to how it already works in C#. https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-10-17.md#properties-with-a-private-accessor

基接口调用,舍入 2 (关闭) Base Interface Invocations, round 2 (closed)

前面的 "解决方法" 是如何处理基本调用,实际上不提供足够的表现力。Our previous "resolution" to how to handle base invocations doesn't actually provide sufficient expressiveness. 事实证明,在 c # 和 CLR 中,与 Java 不同,您需要指定包含方法声明的接口以及要调用的实现的位置。It turns out that in C# and the CLR, unlike Java, you need to specify both the interface containing the method declaration and the location of the implementation you want to invoke.

我建议将以下语法用于接口中的基本调用。I propose the following syntax for base calls in interfaces. 我不喜欢它,但它说明了什么语法必须能够表达:I’m not in love with it, but it illustrates what any syntax must be able to express:

interface I1 { void M(); }
interface I2 { void M(); }
interface I3 : I1, I2 { void I1.M() { } void I2.M() { } }
interface I4 : I1, I2 { void I1.M() { } void I2.M() { } }
interface I5 : I3, I4
{
    void I1.M()
    {
        base<I3>(I1).M(); // calls I3's implementation of I1.M
        base<I4>(I1).M(); // calls I4's implementation of I1.M
    }
    void I2.M()
    {
        base<I3>(I2).M(); // calls I3's implementation of I2.M
        base<I4>(I2).M(); // calls I4's implementation of I2.M
    }
}

如果没有歧义,可以更简单地编写If there is no ambiguity, you can write it more simply

interface I1 { void M(); }
interface I3 : I1 { void I1.M() { } }
interface I4 : I1 { void I1.M() { } }
interface I5 : I3, I4
{
    void I1.M()
    {
        base<I3>.M(); // calls I3's implementation of I1.M
        base<I4>.M(); // calls I4's implementation of I1.M
    }
}

Or

interface I1 { void M(); }
interface I2 { void M(); }
interface I3 : I1, I2 { void I1.M() { } void I2.M() { } }
interface I5 : I3
{
    void I1.M()
    {
        base(I1).M(); // calls I3's implementation of I1.M
    }
    void I2.M()
    {
        base(I2).M(); // calls I3's implementation of I2.M
    }
}

Or

interface I1 { void M(); }
interface I3 : I1 { void I1.M() { } }
interface I5 : I3
{
    void I1.M()
    {
        base.M(); // calls I3's implementation of I1.M
    }
}

决策:确定 base(N.I1<T>).M(s) conceding,如果有调用绑定,稍后会出现问题。Decision: Decided on base(N.I1<T>).M(s), conceding that if we have an invocation binding there may be problem here later on. https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-11-14.md#default-interface-implementations

结构未实现默认方法时的警告?Warning for struct not implementing default method? (关闭) (closed)

@vancem 断言应认真考虑在值类型声明无法重写某些接口方法时产生警告,即使它会从接口继承该方法的实现。@vancem asserts that we should seriously consider producing a warning if a value type declaration fails to override some interface method, even if it would inherit an implementation of that method from an interface. 因为这会导致装箱和会破坏约束调用。Because it causes boxing and undermines constrained calls.

决策:看起来就像是更适合分析器的内容。Decision: This seems like something more suited for an analyzer. 这似乎会干扰此警告,因为即使从未调用默认接口方法,也不会出现任何装箱。It also seems like this warning could be noisy, since it would fire even if the default interface method is never called and no boxing will ever occur. https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-10-17.md#warning-for-struct-not-implementing-default-method

接口静态构造函数 (关闭) Interface static constructors (closed)

何时运行接口静态构造函数?When are interface static constructors run? 当前 CLI 草稿建议在访问第一个静态方法或字段时发生。The current CLI draft proposes that it occurs when the first static method or field is accessed. 如果没有这样做,则可能永远不会运行它?If there are neither of those then it might never be run??

[2018-10-09 CLR 团队提出了 "要镜像为具有的操作 (对每个实例方法的访问) "] 进行的访问[2018-10-09 The CLR team proposes "Going to mirror what we do for valuetypes (cctor check on access to each instance method)"]

决策:如果静态构造函数不是,则静态构造函数也会在输入到实例方法时运行 beforefieldinit ,在这种情况下,将在访问第一个静态字段之前运行静态构造函数。Decision: Static constructors are also run on entry to instance methods, if the static constructor was not beforefieldinit, in which case static constructors are run before access to the first static field. https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-10-17.md#when-are-interface-static-constructors-run

设计会议Design meetings

2017-03-08 LDM 会议笔记 2017-03-21 LDM 会议笔记 2017-03-23 会议 "默认接口方法的 CLR 行为" 2017-04-05 LDM 会议笔记 2017-04-11 LDM 会议笔记 2017-04-18 LDM 会议笔记 2017-04-19 LDM 会议笔记 2017-05-17 LDM 会议笔记 2017-05-31 LDM 会议笔记 2017-06-14 LDM 会议笔记 2018-10-17 LDM 会议笔记 2018-11-14 LDM 会议笔记2017-03-08 LDM Meeting Notes 2017-03-21 LDM Meeting Notes 2017-03-23 meeting "CLR Behavior for Default Interface Methods" 2017-04-05 LDM Meeting Notes 2017-04-11 LDM Meeting Notes 2017-04-18 LDM Meeting Notes 2017-04-19 LDM Meeting Notes 2017-05-17 LDM Meeting Notes 2017-05-31 LDM Meeting Notes 2017-06-14 LDM Meeting Notes 2018-10-17 LDM Meeting Notes 2018-11-14 LDM Meeting Notes