是空的接口代码味道?

我有一个函数返回相同types的对象(查询结果),但没有属性或方法的共同点。 为了有一个通用的types,我使用了一个空接口作为返回types,并且实现了这两个接口。

这当然听起来不对。 我只能抱住自己,希望有一天这些类会有共同的东西,我会把这个共同的逻辑移到我的空白界面。 然而,我并不满意,想着是否应该有两种不同的方法,然后有条件地打电话。 这是一个更好的方法吗?

我也被告知,.NET Framework使用空接口进行标记。

我的问题是:空的界面是devise问题的一个强烈的标志,还是被广泛使用?

编辑 :对于那些感兴趣的,我后来发现,在function语言歧视工会是我想要实现的完美的解决scheme。 C#对这个概念看起来并不友好。

编辑 :我写了一个关于这个问题的更长的篇幅,详细解释了这个问题和解决scheme。

尽pipe这个用例似乎存在一个devise模式(现在很多人提到了“标记接口”),但我相信这种做法的使用是一种代码异味的表示(至less大部分时间)。

正如@ V4Vendetta发布,有一个静态分析规则,目标是: http : //msdn.microsoft.com/en-us/library/ms182128( v=VS.100) .aspx

如果您的devise包含types预期要实现的空接口,那么您可能将接口用作标记或识别一组types的方法。 如果这个标识将在运行时发生,则正确的方法是使用自定义属性。 使用属性的存在或不存在或属性的属性来标识目标types。 如果标识必须在编译时发生,那么使用空的接口是可以接受的。

这是引用MSDN的build议:

删除界面或添加成员。 如果正在使用空接口标记一组types,请使用自定义属性replace该接口。

这也反映了已经发布的维基百科链接的评论部分。

标记接口的一个主要问题是一个接口定义了一个实现类的契约,并且契约被所有的子类inheritance。 这意味着你不能“实现”一个标记。 在给出的例子中,如果你创build了一个你不想序列化的子类(可能是因为它依赖于临时状态),你必须求助于显式抛出NotSerializableException(每个ObjectOutputStream文档)。

你声明你的函数“基于某些情况返回完全不同的对象” – 但是它们有多不同? 可以是一个stream编写器,另一个UI类,另一个数据对象? 不…我怀疑它!

您的对象可能没有任何常用的方法或属性,但是,它们的作用或用法可能相似。 在这种情况下, 标记界面看起来完全合适。

如果不作为标记接口 ,我会说是的,这是一个代码气味。

一个接口定义了一个实现者遵守的契约 – 如果你有空的接口,你不使用reflection(就像标记接口一样),那么你也可以使用Object作为(已经存在的)基types。

你回答了你自己的问题……“我有一个函数根据某些情况返回完全不同的对象。”…为什么你想要有相同的函数返回完全不同的对象? 我看不出这个有用的理由,也许你有一个好的,在这种情况下,请分享。

编辑:考虑到你的澄清,你应该确实使用标记界面。 “完全不同”与“同一种”是完全不同的。 如果他们完全不同(不仅仅是他们没有共享成员),那将是一种代码味道。

正如很多人可能已经说过的那样,一个空的界面确实可以有效地用作“标记界面”。

可以想象的最好的用法是将对象表示为属于特定子域的对象,由对应的Repository处理。 假设您有不同的数据库来检索数据,并且每个数据库都有一个Repository实现。 一个特定的Repository只能处理一个子集,而不能从其他子集中获得一个对象的实例。 您的域模型可能如下所示:

 //Every object in the domain has an identity-sourced Id field public interface IDomainObject { long Id{get;} } //No additional useful information other than this is an object from the user security DB public interface ISecurityDomainObject:IDomainObject {} //No additional useful information other than this is an object from the Northwind DB public interface INorthwindDomainObject:IDomainObject {} //No additional useful information other than this is an object from the Southwind DB public interface ISouthwindDomainObject:IDomainObject {} 

然后,可以使您的存储库与ISecurityDomainObject,INorthwindDomainObject和ISouthwindDomainObject通用,然后编译时检查您的代码是否尝试将安全对象传递给Northwind DB(或任何其他置换)。 在这种情况下,即使没有提供任何实施合同,界面也会提供有关class级性质的宝贵信息。

Interesting Posts