简答
因为接口只包含一个类的定义,并且不能包含任何成员函数的实际实现。这是设计使然。
长答案
首先你必须认识到属性基本上是get 和set 成员函数,具有一些简化的语法。因此这里的问题是:为什么接口定义不能包含成员函数的实现?
嗯,在某些语言中(最著名的是:C++)你可以。
如果你有一个继承链,那基本上是通过查找表来解决的。假设您有成员函数 1,那么在继承链中的所有类中,都有一个包含指向函数 1 的指针的表。一旦调用成员函数,该调用基本上会从属于该类型的表中获取第一个条目你的对象,并称之为。这个东西叫做vtable(更多细节请看here)。
现在,在 C++ 中,VTable 对开发人员来说是非常透明的:每个类基本上都有一个 vtable,并且没有真正的“接口”这样的东西。这也意味着所有类都可以具有实现和成员,例如字段。如果你有一个只有纯虚拟成员的类(例如没有实现的函数),那么你就有了相当于 C++ 的“接口”。
在软件工程中,这些类通常被称为“接口”类,因为它们只包含对正在发生的事情的定义,而不是实际的实现。接口具有很好的特性,它们描述功能而不实际进入细节,因此可以在代码中放置“边界”。这有很多用例,包括(RPC)通信、很多设计模式等等。
在 C++ 中,一个类可以派生自多个类(多重继承),有和没有实现。此外,由于接口实际上更像是“抽象”类而不是 C# 中的“接口”,这意味着您也可以在那里添加功能。因此,前面描述的 vtable 包含指向所有基类中的函数的指针。
当您开始向接口类添加功能时,问题就开始了。对于初学者,假设你有这样的东西(我会用某种 C# 来做):
interface A { Foo(); } // basically an interface.
interface B : A { Foo(); } // another interface
class B : A { void Foo() {...} } // implementation of Foo, inherits A
class D : B,C { } // inherits both B, C (and A via both B and C).
我们感兴趣的是,如果您在课堂上调用Foo 会发生什么D。为此,我们必须为类D 构造一个vtable。基本上这个 vtable 应该是这样的:
Foo() -> C::Foo()
这意味着如果你构造一个D的对象,并调用Foo,你最终会调用Foo类型C的实现:
var tmp = new D();
tmp.Foo(); // calls C::Foo()
当我们将 B 的定义更改为如下内容时,它变得更加困难:
class B : A { void Foo() {...} } // changed into an implementation
再一次,我们尝试为D 类构建vtable,但我们最终遇到了一个问题:
Foo() -> C::Foo() or B::Foo()???
我们在这里面临的问题是:调用该成员时,我们将使用Foo 的什么实现?另外,我们要调用什么构造函数?那么毁灭令呢?在 C++ 中有一种解决方法,称为 虚拟继承。
在设计 .NET 和 C# 语言时,他们考虑了过去的多重继承经验以及虚拟继承的含义,并认为这不仅是一件难以实现的事情,而且充其量也让开发人员感到非常困惑。如您所见,只要添加接口,这些问题就不存在了。
所以,这就是为什么你的界面中不能有属性(或方法)。