实现接口和在C#中应用属性之间的区别

时间:2010-04-19 13:57:40

标签: c# interface attributes

这可能是一个愚蠢的问题,但不管怎样我会问,

我正在阅读“OOP揭秘:Jim Keogh和Mario Giannini的自学指南”第11章,其中涵盖了界面。本书中的例子是C ++。

我注意到C ++使用ISerializable来创建一个可序列化的类,你可以在C#中实现,你只需要使用[Serializable]属性来定义类。

这里的主要区别是什么?是否有了接口,你必须提供实现,就好像你属性一样编译器会为你实现实现?

我想通过[Serializable]属性,.Net框架使用反射从实际对象中生成序列化对象。

那就是说在这种情况下有可能有一个[Disposable]属性或者在框架之上使用我的理论不知道如何实际处理一个对象因此你必须自己做?

非常感谢澄清。

感谢。

6 个答案:

答案 0 :(得分:10)

很久以前在一个遥远的星系......没有属性或编译器支持类元数据,所以开发人员试图实现自己的。我们的祖先制定的方法之一是宣布Marker Interfaces

所以,回答你的问题:自定义属性是标记接口的“演变”。你可以使用两者。但请注意,如果要强制实现对象实现特定方法,则使用简单明了的接口。这就是IDisposable的工作原理,它会强制您实现名为Dispose()的方法。 [Serializable](可能是{C ++示例中的ISerializable)并不强制您实现任何内容,因为运行时只会读取该声明并执行其任务(即序列化对象)。

请注意,C#还有一个ISerializable接口......这是为了让您编写自定义序列化代码,然后由运行时调用。请注意,它不是标记接口,也不是[Serializable]属性的替代,因为您仍需要使用序列化属性标记您的类。

答案 1 :(得分:6)

属性通常提供有关类型或成员的其他元数据;关于允许的内容(const值等)存在很大的局限性,Eric Lippert对interfaces and properties之间可能有启发性的差异提出了一些看法。

接口还有其他一些方面:

  • 他们可以有多个成员
  • 接口背后的
  • 是一些实现(这很关键)
  • 您可以使用接口进行抽象(而不是属性)

然而;在缺点方面,一旦类型实现了接口所有子类型也通过继承实现该接口。对比度属性,可以继承但不想成为。

仅仅因为Foo是可序列化的,这并不意味着Bar:Foo)必须是可序列化的;所以能够在每个级别定义它是很好的 - 虽然实际上我并不认为BinaryFormatter应该是mots序列化代码的关键部分(尽管我会咬我的舌头)。

实际上,如果你检查IL,你会发现[Serializable] 实际上没有作为属性写入 - 它是一个CLI标志(一些编译器魔术)。但这并没有改变事实。

如果您需要做的只是表达元数据(关于类型/成员的事实),属性是理想的。如果您需要表达行为/ API,那么接口。

答案 2 :(得分:5)

大多数属性仅在运行时检查。在编译时检查了一些(参见下面提到的conditional属性)。在大多数情况下,使用属性,您必须使用反射来查看对象是否拥有它并决定从那里做什么。

接口是编译器实现。使用接口,您可以要求参数为方法等实现它。

属性: http://msdn.microsoft.com/en-us/library/z0w1kczw.aspx

接口: http://msdn.microsoft.com/en-us/library/ms173156.aspx

答案 3 :(得分:4)

我认为你错过了.NET(C#)也有一个ISerializable接口的事实:

[Serializable]
class Foo : ISerializable
{
}

该属性是“自定义元数据”,界面是语言功能。

答案 4 :(得分:2)

你在属性中读得太多了。 [Serializable] 非常很少。它由二进制序列化使用,由BinaryFormatter类实现。该类具有非常强大的功能,它可以使用类的公共属性创建类的实例,而无需。它直接将值分配给标记为私有的字段,完全绕过正常的访问规则。

您必须明确授予BinaryFormatter这样做的权利,基本上承认您的类的对象可以顺利地反序列化。您可以通过应用[Serializable]属性来执行此操作。 BinaryFormatter仅检查它是否存在。就是这样。

答案 5 :(得分:1)

我认为这是因为传统上某些属性已被标记为可序列化或不可序列化,这意味着在类级别拥有该属性更有意义。

在运行时检查类的属性与在编译时检查类型有一点性能损失。