在我的界面中,我已经使用setter和getter声明了一个属性。
public interface ITestInterface
{
string AProperty { get; set; }
}
当我编写继承该接口的类时,为什么我需要再次定义这两个属性?
public sealed class MyClass: ITestInterface
{
public string AProperty { get; set; }
}
答案 0 :(得分:4)
因为您没有从接口继承,所以您正在实现该接口。 (尽管它们共享相同的语法:
)
public class MyClass : IMyInterface { ... } //interface implementing
public class MyClass : MyBaseClass { ... } //inheriting from a class
假设你继承了一个糖果盒(不是来自你的祖先,以编程的方式),它就像你把糖果盒放在另一个盒子里的东西(不完全一样),现在是外盒子(派生类,继承的盒子) )是从糖果盒继承并拥有糖果盒所有的东西,但是如果你想自己实施(制作)糖果盒,你必须建立一个盒子并放入一些糖果。这是界面工作的方式。
答案 1 :(得分:2)
您的接口定义仅告知存在具有getter和setter的属性,而不是它的实现方式。您可以使用自动实现的属性,但不需要。
在接口之后,这将是一个有效的实现:
public sealed class MyClass: ITestInterface
{
public string APROPERTY
{
get { return someField + " hello"; }
set { someOtherField = value; }
}
}
在接口定义中,string AProperty { get; set; }
是属性的声明,而在类中,这意味着属性自动实现。< / p>
答案 2 :(得分:2)
简短回答
因为接口只包含类的定义,并且不能包含任何成员函数的实际实现。这是设计的。
答案很长
首先,你必须意识到属性基本上是 get 和 set 成员函数,并带有一些简化的语法。因此,这里的问题是:为什么接口定义不能包含成员函数的实现?
嗯,在某些语言中(最值得注意的是:C ++),你可以。
如果你有一个继承链,那基本上是通过查找表来解决的。假设您有成员函数1,那么在继承链的所有类中,都有一个包含指向函数1的指针的表。一旦调用成员函数,该调用基本上从属于该类型的表中获取第一个条目您的对象,并调用它。这个东西叫做 vtable (有关详细信息,请参阅here)。
现在,在C ++中,VTables对开发人员来说非常透明:每个类基本上都有一个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#语言时,他们考虑了过去的多重继承经验以及虚拟继承的含义,并认为这不仅是一件难以实现的事情,而且对于开发人员来说也是非常困惑的。如您所见,当您只是添加接口时,这些问题不存在。
所以,这就是你的界面中没有属性(或方法)的原因。
答案 3 :(得分:0)
答案 4 :(得分:0)
我认为这里的问题是,相同的语法对于接口和类有两种不同的含义。 AProperty { get; set; }
在接口中只是声明,在类中它是一个自动实现的接口。
因此该术语取决于上下文。
public interface ITestInterface
{
string AProperty { get; set; }
}
声明属性,但无法实现它。
public sealed class MyClass: ITestInterface
{
public string AProperty { get; set; }
}
实现接口,其中属性自动实现(仅适用于类)。
答案 5 :(得分:0)
正如其他人所说,interface只是方法和属性签名的容器。它需要实现,但是这个实现签名将与接口中使用的签名完全匹配。此外,它保证所有这些成员都可以在类实例中访问,因为它们是默认的公共属性,没有实现程序根本不会编译。
让我们说你有界面:
public interface ITestInterface
{
string AProperty { get; }
}
和实现它的类:
class MyClass : ITestInterface
{
public string AProperty { get { if (DateTime.Today.Day > 7) return "First week of month has past"; return "First week of month is on"; } }
}
无法使用自动实现的属性,也无法在此类中添加setter,因为interface属性缺少set accessor,自动实现的属性要求该接口包含自动实现的属性签名({get; set ;})。因此,在您的示例界面中,只需声明属性即可。
只要知道接口类继承了什么,就会知道成员是什么,如果你只是想使用(或允许用户使用)这些方法中的一些(不允许改变任何东西),你总是可以向上转换你的类实例到其中一个接口类型并将其作为参数传递。
答案 6 :(得分:0)
我认为这里的混淆来自于自动属性(只是get和/或set声明)在接口和实现中看起来相同。接口仅仅是类必须提供的声明(契约)才能被视为接口的实现者。如果您考虑接口中的方法声明与其在类中的实现相比,则会更清楚。
接口=要求; Class =如何满足这些要求
public interface ITestInterface
{
string GetAProperty();
}
public class MyClass : ITestInterface
{
public string GetAProperty()
{
// Do work...
return "Value";
}
}