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