为什么C#接口不能包含字段?

例如,假设我想要一个ICar接口,并且所有实现都将包含字段Year 。 这是否意味着每个实施都需要单独申报Year ? 在界面中简单地定义它会不会更好?

11 Solutions collect form web for “为什么C#接口不能包含字段?”

虽然许多其他的答案在语义层面上是正确的,但是我觉得从实现细节层面来处理这些问题也是很有趣的。

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

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

这个class级说:“当你创build我的一个实例时,在IFoo.M的插槽中填入对Foo.M的引用。

那么当你打电话时:

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

编译器生成的代码是“询问对象在IFoo.M的槽中有什么方法,然后调用该方法。

如果接口是包含方法的槽的集合,那么其中一些槽也可以包含属性的get和set方法,索引器的get和set方法,以及事件的add和remove方法。 但是一个领域不是一个方法 。 没有“插槽”与一个字段相关联,然后您可以通过引用字段位置“填写”。 因此,接口可以定义方法,属性,索引器和事件,但不能定义字段。

C#中的接口旨在定义一个类将遵守的合同 – 而不是一个特定的实现。

本着这种精神,C#接口允许定义属性 – 调用者必须提供一个实现:

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

如果没有与属性相关联的特殊逻辑,实现类可以使用自动属性来简化实现:

 class Automobile : ICar { public int Year { get; set; } // automatically implemented } 

将其声明为属性:

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

Eric Lippert指出,我会用不同的方式说出他所说的话。 接口的所有成员都是虚拟的,它们都需要由inheritance接口的类重写。 你没有在接口声明中明确写出virtual关键字,也没有在类中使用override关键字。

virtual关键字在.NET中用方法和所谓的v-表(一个方法指针数组)来实现。 override关键字用不同的方法指针填充v表插槽,覆盖基类生成的。 属性,事件和索引器被实现为引擎盖下的方法。 但田野不是。 接口因此不能包含字段。

为什么不只是有一个Year财产,这是非常好的?

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

例如,你的Year规范的一部分可能要求ICar实现者允许分配到一个比当前年份+ 1还晚的年份。无法说如果你已经暴露了Year字段 -更好地使用属性,而不是在这里做的工作。

简单的答案是肯定的,每个实现types将不得不创build自己的支持variables。 这是因为接口类似于合同。 它所能做的只是指定一个实现types必须提供的特定的可公开访问的代码段; 它本身不能包含任何代码。

考虑这个场景使用你的build议:

 public interface InterfaceOne { int myBackingVariable; int MyProperty { get { return myBackingVariable; } } } public interface InterfaceTwo { int myBackingVariable; int MyProperty { get { return myBackingVariable; } } } public class MyClass : InterfaceOne, InterfaceTwo { } 

这里有几个问题:

  • 因为接口的所有成员都是按照定义public的,所以我们的支持variables现在暴露给使用接口的任何人
  • MyClass将使用哪个myBackingVariable

最常用的方法是声明接口和一个实现它的准系统抽象类。 这允许您灵活地从抽象类inheritance并获得免费的实现,或者显式地实现接口并被允许从另一个类inheritance。 它的工作原理是这样的:

 public interface IMyInterface { int MyProperty { get; set; } } public abstract class MyInterfaceBase : IMyInterface { int myProperty; public int MyProperty { get { return myProperty; } set { myProperty = value; } } } 

其他人给了“为什么”,所以我只是补充说,你的界面可以定义一个控制; 如果你把它包装在一个属性中:

 public interface IView { Control Year { get; } } public Form : IView { public Control Year { get { return uxYear; } } //numeric text box or whatever } 

接口不包含任何实现。

  1. 定义一个属性的接口。
  2. 此外,你可以在任何类中实现该接口,并继续使用这个类。
  3. 如果需要,您可以在该类中将此属性定义为虚拟,以便您可以修改其行为。

已经有很多人说过了,但为了简单起见,这是我的看法。 接口旨在使方法合约由消费者或类实现,而不是有字段来存储值。

你可能会争辩说,为什么房地产被允许? 所以简单的答案是 – 属性被内部定义为只有方法。

为此,您可以有一个Car基类实现年份字段,所有其他实现可以inheritance它。

一个接口定义了公共实例的属性和方法。 领域通常是私人的,或在最受保护的,内部的或受保护的内部(术语“领域”通常不用于任何公开的)。

正如其他答复所述,您可以定义一个基类并定义一个受所有inheritance者访问的受保护的属性。

一个奇怪的是,一个接口实际上可以定义为内部接口,但是它限制了接口的有效性,通常用于定义其他外部代码没有使用的内部function。