例如,假设我想要一个ICar接口,并且所有实现都将包含字段Year。这是否意味着每个实现都必须单独声明Year?在接口中简单地定义它不是更好吗?


当前回答

为什么不使用Year属性呢?

接口不包含字段,因为字段表示数据表示的特定实现,暴露它们会破坏封装。因此,拥有一个带有字段的接口将有效地编码到一个实现,而不是一个接口,这是一个奇怪的接口!

例如,部分Year规范可能要求ICar实现者允许赋值给比当前年份+ 1晚或1900年之前的年份是无效的。如果您已经公开Year字段,就无法这样说——在这里使用属性来完成工作要好得多。

其他回答

将其声明为属性:

interface ICar {
   int Year { get; set; }
}

为此,您可以有一个实现year字段的Car基类,所有其他实现都可以从它继承。

尽管许多其他答案在语义层面上是正确的,但我发现从实现细节层面处理这类问题也很有趣。

接口可以看作是插槽的集合,插槽包含方法。当一个类实现一个接口时,该类需要告诉运行时如何填充所有必需的插槽。当你说

interface IFoo { void M(); } 
class Foo : IFoo { public void M() { ... } }

这个类说:“当你创建一个我的实例时,填充一个对Foo的引用。M在IFoo.M的槽里。

然后当你打电话的时候:

IFoo ifoo = new Foo();
ifoo.M();

编译器会生成这样的代码:“询问对象IFoo的槽中有哪个方法。M,然后调用这个方法。

如果接口是包含方法的槽的集合,那么其中一些槽还可以包含属性的get和set方法、索引器的get和set方法以及事件的添加和删除方法。但是字段不是方法。没有与字段相关联的“槽”,然后您可以用字段位置的引用“填充”该字段。因此,接口可以定义方法、属性、索引器和事件,但不能定义字段。

接口定义了公共实例属性和方法。字段通常是私有的,或者至多是受保护的、内部的或受保护的内部的(术语“字段”通常不用于任何公共的内容)。

正如其他回复所述,您可以定义一个基类并定义一个受保护的属性,该属性将被所有继承者访问。

一个奇怪的地方是,一个接口实际上可以被定义为内部的,但它限制了接口的有用性,并且它通常用于定义其他外部代码不使用的内部功能。

Eric Lippert说的很好,我会用另一种方式来表达他说的话。接口的所有成员都是虚的,它们都需要被继承该接口的类重写。你不需要在接口声明中显式地编写virtual关键字,也不需要在类中使用override关键字,它们是隐含的。

在. net中,virtual关键字是通过方法和所谓的v-table(方法指针数组)实现的。override关键字用不同的方法指针填充v-table槽,覆盖基类生成的方法指针。属性、事件和索引器是作为方法实现的。但是田野不是。因此,接口可以不包含字段。