使用 I 作为接口名称前缀的 .NET 标准似乎越来越普遍,并且不再仅限于 .NET。我遇到了很多使用这种约定的 Java 代码(所以如果 Java 在 C# 之前使用它,我不会感到惊讶)。Flex 也使用它,等等。不过,在名称的开头放置一个 I 有点匈牙利符号的味道,所以我对使用它感到不舒服。
所以问题是,是否有另一种方式来表示Something 是一个接口,而不是一个类,并且无论如何都需要这样表示它。还是它成为一个标准,所以我应该接受它并停止试图通过建议以不同的方式来挑起“宗教战争”?
使用 I 作为接口名称前缀的 .NET 标准似乎越来越普遍,并且不再仅限于 .NET。我遇到了很多使用这种约定的 Java 代码(所以如果 Java 在 C# 之前使用它,我不会感到惊讶)。Flex 也使用它,等等。不过,在名称的开头放置一个 I 有点匈牙利符号的味道,所以我对使用它感到不舒服。
所以问题是,是否有另一种方式来表示Something 是一个接口,而不是一个类,并且无论如何都需要这样表示它。还是它成为一个标准,所以我应该接受它并停止试图通过建议以不同的方式来挑起“宗教战争”?
从框架设计指南书:
表示层次结构根的接口(例如 IList)也应该使用名词或名词短语。表示能力的接口应该使用形容词和形容词短语(例如 IComparable、IFormattable)。
另外,从接口命名的注释中:
KRZYSZTOF CWALINA:少数使用的前缀之一是“I”表示接口(如在 ICollection 中),但这是出于历史原因。回想起来,我认为使用常规类型名称会更好。例如,在大多数情况下,开发人员并不关心某个东西是接口而不是抽象类。
BRAD ABRAMS:另一方面,接口上的“I”前缀清楚地认识到 COM(和 Java)对 .NET Framework 的影响。COM 普及甚至制度化了接口以“I”开头的符号。尽管我们讨论了与这种历史模式不同的问题,但我们决定继续使用这种模式,因为我们的许多用户已经熟悉 COM。
JEFFREY RICHTER:就个人而言,我喜欢“I”前缀,我希望我们有更多这样的东西。小的单字符前缀对保持代码简洁和描述性大有帮助。正如我之前所说,我对私有类型字段使用前缀,因为我发现这非常有用。
BRENT RECTOR 注意:这实际上是匈牙利符号的另一种应用(尽管没有符号在变量名中使用的缺点)。
它已经成为一种广泛采用的标准,虽然它是匈牙利语的一种形式,正如 Brent 所说,但它没有在变量名中使用匈牙利语表示法的缺点。
老实说,我会接受它。我知道您所说的有点像匈牙利符号(或至少滥用相同符号)是什么意思,但我认为在这种情况下它具有足够的价值值得做。
随着依赖注入的流行,我经常发现我最终得到了一个接口和一个单一的生产实现。只需使用 I 前缀就可以很方便地区分它们。
一个小数据点:我大量使用 Java 和 C#,并且我经常发现自己必须检查 Java 中的哪些类型实际上是接口,尤其是在集合框架周围。.NET 让这一切变得简单。也许它不会打扰其他人,但它会打扰我。
我为 IFoo +1。
作为一个 .NET 程序员(在大多数情况下),我实际上更喜欢 Java 约定将其删除I
,原因很简单:通常,小的重新设计需要从接口更改为抽象基类,反之亦然。如果您必须更改名称,这可能需要进行大量不必要的重构。
另一方面,客户端的使用应该是透明的,因此他们不应该关心这种类型的提示。此外,“Thingable”中的“able”后缀应该足够暗示了。它在 Java 中运行良好。
/编辑:我想指出,上述推理促使我放弃了I
私人项目的前缀。但是,根据 FxCop 规则集检查其中一个后,我立即恢复使用I
. 一致性在这里获胜,即使愚蠢的一致性是小头脑的妖精。
它的所有关于样式和可读性。在接口前加上“I”只是一种流行的命名约定和风格指南。编译器本身并不在乎。
我的主要假设是,最重要的是保持实现的域部分的可读性。所以:
如果您有一种行为和一种可能的实现,那么就不要创建接口:
public class StackOverflowAnswerGenerator { }
如果您有一种行为和许多可能的实现,那么没有问题,您可以删除“I”,并拥有:
public interface StackOverflowAnswerGenerator {}
public class StupidStackOverflowAnswerGenerator : StackOverflowAnswerGenerator {}
public class RandomStackOverflowAnswerGenerator : StackOverflowAnswerGenerator {}
public class GoogleSearchStackoverflowAnswerGenerator : StackOverflowAnswerGenerator {}
//...
当您有一种行为和一种可能的实现时,真正的问题就出现了,但您需要一个接口来描述其行为(例如,为了方便测试,由于项目中的约定,使用一些强制执行此操作的库/框架,...)。可能的解决方案,除了为接口添加前缀之外,还有:
a)为实现添加前缀或后缀(如本主题的其他一些答案中所述)
b)为接口使用不同的命名空间:
namespace StackOverflowAnswerMachine.Interfaces
{
public interface StackOverflowAnswerGenerator {}
}
namespace StackOverflowAnswerMachine
{
public class StackOverflowAnswerGenerator : Interfaces.StackOverflowAnswerGenerator
{}
}
c)使用不同的命名空间进行实施:
namespace StackOverflowAnswerMachine
{
public interface StackOverflowAnswerGenerator {}
}
namespace StackOverflowAnswerMachine.Implementations
{
public class StackOverflowAnswerGenerator : StackOverflowAnswerMachine.StackOverflowAnswerGenerator
{}
}
尽管我认为最后一种可能性是最干净的,但它的一个缺点是即使using StackOverflowAnswerMachine;
您可以访问所有域对象,您也必须为所有域接口添加前缀,以免与它们的实现混淆。这可能感觉不是很方便,但在干净的设计中,通常一个类不使用许多其他域对象,并且大多数情况下您只需要在字段声明和构造函数参数列表中使用前缀。所以,这是我目前的建议。
域功能的客户端不需要知道他们使用的是接口、抽象类还是具体类。如果他们需要知道这一点,那么在这样的项目中就会出现一些严重的问题,因为它在同一个抽象层上混合了领域逻辑和基础设施问题。因此我推荐“ a ”或“ c ”解决方案。
Symbian 的编码标准具有用 M 而不是 I 表示的接口(纯抽象 C++ 类)。
否则,我见过的表示接口的唯一其他方式是通过上下文。
对于 .NET,Microsoft 的框架设计指南一书绝对推荐它,是的,它非常标准。我从来没有见过它这样做,创建一个新的公约只会使人们感到困惑。
我应该补充一点,我也不喜欢匈牙利符号,但是这种情况以及在类变量前加下划线的情况对我来说是一个很好的例外,因为它们使代码更具可读性。
我一直认为这种命名约定有点像恐龙。如今,IDE 已经足够强大,可以告诉我们某物是一个接口。补充一点,我会使代码更难阅读,所以如果你真的想要一个将接口与类分开的命名约定,我会将 Impl 附加到实现类的名称中。
public class CustomerImpl implements Customer
您要求另一种选择,所以这是我遇到的一种:
在接口类上不使用前缀,但在相应的具体类上使用c或C前缀。您的大多数代码通常会引用接口,所以为什么要使用前缀而不是通常使用较少的具体类型来污染它。
这种方法确实引入了一个不一致之处,即某些具体类型将被添加前缀(具有匹配接口的类型)而其他类型则不会。这可能很有用,因为它提醒开发人员存在接口,并且应该优先使用它而不是具体类型。
老实说,我在界面上使用了前缀,但我认为更多是因为我已经习惯和习惯了它。