例如,假设我想要一个ICar
接口,并且所有实现都将包含field Year
。这是否意味着每个实现都必须单独声明Year
?在界面中简单地定义它会更好吗?
例如,假设我想要一个ICar
接口,并且所有实现都将包含field Year
。这是否意味着每个实现都必须单独声明Year
?在界面中简单地定义它会更好吗?
Answers:
尽管许多其他答案在语义级别上都是正确的,但我发现从实现细节级别也解决此类问题很有趣。
接口可以看作是插槽的集合,其中包含方法。当类实现接口时,需要该类告诉运行时如何填写所有必需的插槽。当你说
interface IFoo { void M(); }
class Foo : IFoo { public void M() { ... } }
该类说:“当您创建我的实例时,请在IFoo.M的插槽中填充对Foo.M的引用。
然后,当您拨打电话时:
IFoo ifoo = new Foo();
ifoo.M();
编译器生成的代码表明“向对象询问IFoo.M插槽中的方法是什么,然后调用该方法。
如果接口是包含方法的插槽的集合,那么这些插槽中的某些插槽也可以包含属性的get和set方法,索引器的get和set方法以及事件的add和remove方法。但是领域不是方法。没有与该字段关联的“插槽”,然后您可以通过引用该字段位置来“填写”。因此,接口可以定义方法,属性,索引器和事件,但不能定义字段。
An interface cannot contain constants, fields, operators
从。msdn.microsoft.com/en-us/library/ms173156.aspx)
int One()
,则实现public int One(){return 1;}
不是一个字段。
C#中的接口旨在定义类将遵守的协定-而不是特定的实现。
本着这种精神,C#接口确实允许定义属性-调用者必须为以下属性提供实现:
interface ICar
{
int Year { get; set; }
}
如果没有与属性相关的特殊逻辑,则实现类可以使用自动属性来简化实现:
class Automobile : ICar
{
public int Year { get; set; } // automatically implemented
}
Year
?
public int Year => 123;
。但是,在这种情况下,没有设置器是没有意义的,因此必须使用int Year { get; }
声明为属性:
interface ICar {
int Year { get; set; }
}
埃里克·利珀特(Eric Lippert)钉上了钉子,我将用另一种方式来表达他的意见。接口的所有成员都是虚拟的,它们都需要被继承该接口的类覆盖。您没有在接口声明中显式地编写virtual关键字,也没有在类中使用override关键字,这是隐含的。
virtual关键字是在.NET中使用方法和所谓的v表(方法指针数组)实现的。overlay关键字使用不同的方法指针填充v-table插槽,从而覆盖了基类产生的指针。属性,事件和索引器在后台被实现为方法。但是领域却不是。因此,接口不能包含字段。
简短的答案是肯定的,每个实现类型都必须创建自己的支持变量。这是因为接口类似于合同。它所能做的就是指定实现类型必须提供的特定的公共可访问代码段。它本身不能包含任何代码。
使用您的建议考虑这种情况:
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 { }
这里有两个问题:
myBackingVariable
会MyClass
用?最常用的方法是声明接口和实现该接口的准系统抽象类。这使您可以灵活地从抽象类继承并免费获得实现,或者显式实现接口并被允许从另一个类继承。它的工作原理如下:
public interface IMyInterface
{
int MyProperty { get; set; }
}
public abstract class MyInterfaceBase : IMyInterface
{
int myProperty;
public int MyProperty
{
get { return myProperty; }
set { myProperty = value; }
}
}
已经说了很多,但是为了简单起见,这是我的观点。接口旨在具有要由使用者或类实现的方法协定,而不要具有用于存储值的字段。
您可能会争辩说,为什么要允许使用属性?因此,简单的答案是-属性在内部仅定义为方法。
为此,您可以有一个实现年份字段的Car基类,所有其他实现都可以从中继承。