为什么 C# 接口名称前面加上“I”前缀?

发布于 2024-07-11 07:51:16 字数 280 浏览 9 评论 0原文

这种命名约定背后的基本原理是什么?

我没有看到任何好处。 额外的前缀只会污染 API。

我的想法与康拉德对此相关的回应一致问题; 所选择的答案主要是我在这里要求的。

What is the rationale behind this naming convention?

I don't see any benefit. The extra prefix just pollutes the API.

My thinking is inline with Konrad's response to this related question; the chosen answer of which is mostly what I am asking for here.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(18

〆一缕阳光ご 2024-07-18 07:51:17

区分接口和类的需要实际上表明了设计缺陷。 在设计良好的应用程序中,它总是清晰的。 子类应该始终是专门化的,并且类只能专门化一个主题,而不能再专门化。

一个类应该有一个单一的存在理由。 永远不应该要求将次要角色放入基类中。 例如:

public class XmlConfigurationFile : ConfigurationFile, IDisposable
{
}

public class YamlConfigurationFile : ConfigurationFile, IDisposable
{
}

第一个是专门用于 Xml 的配置文件,第二个是专门用于 Yaml 的配置文件。 这些也是一次性的,但这并不重要。 由于处理过程不同,您没有创建这两个类。

与之对比:

public class XmlConfigurationFile : IDisposable, ConfigurationFile
{
}

这将告诉您 XmlConfigurationFile 的主要用途是它是一次性的。 您可以使用它作为表示配置文件的方式很好,但这是次要的。

当您创建有多种存在原因的类时,问题就开始了:

public class MyConfigurationFile : XmlConfigurationFile, YamlConfigurationFile
{
}

即使 XmlConfigurationFile 和 YamlConfigurationFile 是接口,它仍然表明设计不好。 你的配置文件怎么可能同时是Xml和Yaml呢?

如果你通读给出的例子(这里和其他地方),人们总是很难找到一个很好的例子来说明 I 前缀何时很重要。 这里的答案之一是:

public class Dog : Pet, Mammal
{
}

这就是此类在有关宠物的应用程序中的样子。 狗的主要目的是成为一种专门的宠物,可以做与宠物相关的事情,而不是因为它是哺乳动物。

public class Dog : Mammal, Pet
{
}

这就是同一个类在动物分类应用程序中的样子。 很高兴知道狗是宠物,但它的主要目的是成为一种特殊的哺乳动物,可以做与哺乳动物相关的事情。

我认为您的课程应该告诉您有关应用程序的架构和领域的正确故事。 要求接口以“I”为前缀是一项技术要求,并不能帮助您更好地讲述应用程序的故事。

一旦您开始编写小型、专用、单一用途的类,了解它是否实现或扩展的需要将自动消失。

The need to differentiate between an interface and a class actually indicates a design flaw. In a well designed application, it will always be clear. A subclass should always be a specialization and classes can only be specialized in one subject, never more.

A class should have a single reason for existence. It should never be required to put secondary roles in a base class. E.g.:

public class XmlConfigurationFile : ConfigurationFile, IDisposable
{
}

public class YamlConfigurationFile : ConfigurationFile, IDisposable
{
}

The first one is a configuration file that is specialized in Xml, the second one is specialized in Yaml. These are also disposable, but that doesn't matter as much. You didn't create these two classes because of a different disposing processes.

Constrast this with:

public class XmlConfigurationFile : IDisposable, ConfigurationFile
{
}

This will tell you that the main purpose a XmlConfigurationFile has, is that it is disposable. That you can use it as a way to represent configuration files is nice, but is secondary.

The problem starts when you create classes that have multiple reasons for existence:

public class MyConfigurationFile : XmlConfigurationFile, YamlConfigurationFile
{
}

Even if XmlConfigurationFile and YamlConfigurationFile would have been interfaces, it still indicates bad design. How can your configuration file be Xml and Yaml at the same time?

If you read through the examples given (here and elsewhere), people always struggle to find a good example of when the I-prefix matters. One of the answers here is:

public class Dog : Pet, Mammal
{
}

This is how this class will look like in an application about pets. A dog's main purpose is being a specialized pet, that can do pet-related things, not that it is a mammal.

public class Dog : Mammal, Pet
{
}

This is how the same class will look like in an application about animal classifications. It is nice to know a dog is a pet, but it's main purpose is being a specialized mammal, that can do mammal-related things.

I think your classes should tell you the correct story about the architecture and domain of your application. Requiring an interface to be prefixed with an 'I' is a technical requirement and doesn't help you to tell your application's story better.

Once you start writing small, dedicated, single-purpose classes, the need for knowing if it implements or extends will automatically vanish.

初心未许 2024-07-18 07:51:17

它使得它很容易被识别为一个接口。

It makes it easily identifiable as an interface.

扭转时空 2024-07-18 07:51:17

TL;DR - 从 class Foo 中提取 interface IFoo 在 SOLID 解耦中很常见,特别是出于单元测试的目的

对我来说,类 的双重约定 < code>Foo 实现接口 IFoo(特别是如果两者都在同一个程序集中)传达了一个特定的意图:

  • Foo 的依赖耦合应该始终是间接,通过相应的 IFoo 接口(并且可能通过 IoC 容器注入)。
  • IFoo 的初始设计是一个专有的、不可重用的接口,专门用于允许类依赖在 Foo 上以在单元测试期间模拟此依赖关系。
  • 除此之外,读者不需要在 IFoo 接口的设计中推断任何额外的智能。
  • 相反,如果稍后需要多个 IFoo 的具体实现类值得注意的是,适当的接口隔离设计需要在层次结构中进行改造。

基本原理

为了能够模拟或存根一个类,单元测试中广泛接受的最佳实践是仅通过接口解耦类之间的依赖关系。 此接口解耦也将对类进行,否则从来没有多态性的设计需求(即,如果不是因为需要单元测试,则只会存在一个这样的实现)。

因此,这些接口的重构和重用(例如 SOLID 的接口隔离原则) 并不经常应用于此类“可模拟”接口 - “可模拟”类的公共方法、属性和事件之间通常存在 1:1 的相关性 (Foo )及其解耦接口 IFoo (类似于 COM 时代的 VB 中的自动接口)。

VS 和 Resharper 等工具可以从类变成一个单独的接口是微不足道的,作为事后的想法。

此外,如果我们认为像 Moq 这样的 Mocking 框架允许定义接口的实现-fly,我们不需要浪费精力命名具体的测试替身实现类。

TL;DR - Extracting interface IFoo from class Foo is common in SOLID decoupling, especially for Unit Testing purposes

To me the dual convention of class Foo implementing interface IFoo (especially if both are in the same assembly) conveys a specific intention that:

  • Coupling on a dependency to a Foo should always be indirect, through the corresponding IFoo interface (and likely to be injected via an IoC container)
  • The initial design of IFoo is a proprietary, non-reusable interface specifically to allow classes dependent on Foo to mock out this dependency during unit testing.
  • Beyond the above, a reader doesn't need to infer any additional intelligence in the design of the IFoo interface
  • Conversely, if multiple concrete implementation classes of IFoo are required at a later point, that proper interface segregation design will need to be retrofitted into the hierarchy.

Rationale

In order to be able to Mock or Stub out a class, a widely accepted best practice in Unit Testing is to decouple dependencies between classes only via interfaces. This interface decoupling will also be done to classes which would otherwise never had a design requirement for polymorphicism (i.e. only one such implementation would have existed, were it not for the need for unit testing).

As a consequence, the refactoring and reuse of these interfaces (e.g. the Interface Segregation Principal of SOLID) isn't frequently applied to such 'mockable' interfaces - there is often a 1:1 correlation between the public methods, properties and events of a 'mockable' class (Foo) and its decoupled interface IFoo (similar to the COM-era automatic interfaces in VB).

Tools such as VS and Resharper can make extracting such public symbols from a class into a separate interface trivial, as an afterthought.

Further, if we consider that Mocking frameworks like Moq allow definition of implementations of the interface on-the-fly, we need not waste effort naming the concrete test double implementation class.

粉红×色少女 2024-07-18 07:51:17

命名约定的好处是可以在使用对象之前告诉您有关该对象的一些信息。 命名约定已广泛使用多年,可以追溯到 Fortran 坚持将整数值限制为(如果我没记错的话)变量名称,如“i”和“j”。

匈牙利表示法将命名约定提升到了一个全新的丑陋水平,它描述了变量类型,无论它是否是指针等。我们中的许多人接触了大量带有匈牙利表示法的代码,都出现了紧张抽搐和言语结巴的情况。

在接口名称前加上 I 是一种影响相对较小、无害的识别该对象的方法。

Naming conventions offer the benefit of telling you something about the object before you use it. Naming conventions have been widely used for many years, going all the way back to fortran's insistence that integer values were restricted (if I remember correctly) to variable names like "i" and "j".

Hungariation notation took naming conventions to a whole new ugly level tha described the variable type, whether or not it was a pointer, etc. Many of us who were exposed to lots of code with Hungarian notation developed nervous twitches and verbal stutters.

Prefixing interface names with I is a relatively low-impact, harmless way of identifying that object.

唱一曲作罢 2024-07-18 07:51:17

这只是一个命名约定,所以每个人都会知道它是一个接口还是其他东西,它不是编译器或 IDE 强制的,但我一生中看到的所有接口都以字母 I 开头

It is just a naming convention so everybody would know if it is an interface or something else it is not mandatory nor by the compiler nor by the IDE but All the interfaces i saw in my entire life starts with the letter I

花之痕靓丽 2024-07-18 07:51:17

我似乎遵循匈牙利表示法的传统惯例。
接口命名指南说“前缀接口用字母 I 命名,表明该类型是一个接口。”
框架设计指南还指出“请在接口名称前添加字母 I,表明该类型是一个接口。”

这只是一种编码约定,因此很难确定好坏。
重要的是一致性。

I seems to traditional convention from Hungarian Notation.
Interface Naming Guidelines says "Prefix interface names with the letter I, to indicate that the type is an interface."
Framework Design Guidelines also says "DO prefix interface names with the letter I, to indicate that the type is an interface."

It is just a coding convention, So it's to hard to determine good or bad.
Important things is consistency.

橘虞初梦 2024-07-18 07:51:17

首先,我认为在描述中添加 I 前缀是错误的,因为这意味着实现可以有更短的名称。 IList(intf)-> 列表。 这是一种反模式,因为我们都知道在创建时应该使用 intf 并且可能只使用具体类型。 不要激怒我,这是一个概括,但前提是 intf 很少 impl 。 实现名称应该描述它如何实现 intf 或它正在做什么。 想想 intf List、LinkedList,它使用链表实现 List。 谁在乎它是否更长,因为我们大部分时间都应该使用 List。 如果我们有一个实现许多 intf 的类,我们可能不应该包含所有 intf 作为类的真正用途的影子。 在这种情况下,删除一些没有 intf 的内容是有意义的。 例如,人们称呼我的名字而不是个人、兄弟姐妹、开发人员等,使用我的名字是最好的最具描述性的名字。 我想如果一个类是 impl 一个简单的 intf,那么将其称为 Default Intf,这使得它成为 Intf 的默认实现。
类的名称最终应该是人类可读的,并且几乎是描述其目的的简短短语。 前缀代码等并不是很好,因为我们用单词而不是代码进行交流。 计算机不关心类被称为什么,所以剩下的就是我们命名事物,以便这些名称可以帮助我们和我们的同事。

Firstly I believe prefixing with I then description is wrong because it means implementations can have a shorter name. IList (intf) -> List. This is an anti-pattern as we all know we should be using intf and probably only concrete types when creating. Don't flame me this is a generalization but the premise is intf only impl rarely. The implementation name should describe how it's implementing the intf or what it's doing. Think intf List, LinkedList which implements List using a linked list. Who cares if it's longer as we should be using List most of the time. If we have a class implementing many intf we probably should not include all the intf as the shadows the real purpose of the class. IN the case something removed without the intf makes sense. Eg ppl call me by name not Person, Sibling, developer etc using my name is the best most descriptive name. I suppose if a class is impl a simple intf then call it Default Intf which makes it on ious this is the default implementation of Intf.
Names of classes sHould in the end be human readable and almost a short phrase describing their purpose. Prefix codes etc are not great as we communicate with words not codes. Computers do t cAre what classes are called so why remains is that we name things so the names help us and our colleagues.

一向肩并 2024-07-18 07:51:17

最有可能的是,它可以在智能感知中轻松识别,因为所有接口都会聚集在一起。 类似于我为所有 UI 控件添加 btn、tb、lb 前缀的方式。当智能感知启动时,所有内容都会聚集在一个简单的组中。

Most likely its to make it easily identifiable in intellisense, since all the interfaces will clump together. Similar to how I prefix all my UI controls with btn, tb, lb. When intellisense kicks in everything is clumped together in one easy group.

夜深人未静 2024-07-18 07:51:17

关于命名约定以及为实际描述其用途的变量和方法提供正确名称的所有争论......为什么不直接命名您的接口(例如 PetInterface、PlayerInterface 等)并去掉前缀“I”一起。 所以你必须额外输入9个字母,至少去掉“I”,我们知道它不是一个类,因为它说的是“Interface”。

With all of the arguments about naming conventions and giving proper names to variables and methods that actually describe what they do...why not just name your interfaces (e.g. PetInterface, PlayerInterface, etc.) and do away with the prefix "I" all together. So what you have to type an additional 9 letters, at least the "I" is removed and we know it is not a class, because it says "Interface".

东风软 2024-07-18 07:51:16

完全相反,命名约定清楚地标识了一个接口。

例如,如果您有:

public class Dog : IPet, IMammal
{
    ....

只要阅读它,我就可以放心地假设 IPet 和 IMammal 可能是接口。

.NET CLR 允许单个类继承。 所以,如果我有一个基类......我只能从中继承一个类。 让我们将 IPet 接口更改为基类。我们的示例现在变为

public class Dog : Pet, IMammal
{
    ....

我继承 Pet 类并实现 IMammal 接口。

如果我们按照您的建议进行操作并删除了字母“I”,我们就会得到以下结果:

public class Dog : Pet, Mammal
{
    ....

我继承的类是哪一个? 我正在实现哪个接口? 它变得令人困惑吧? 参考......你应该总是把基类放在第一位,所以你可以争论这一点......但是如果你争论从接口名称前缀中删除字母 I 我怀疑你也遵循这种做法)

(仅供 看到命名约定很容易告诉我很多关于我的对象的信息,而无需我进一步调查。 我可以轻松地看到我继承的内容与我正在实施的内容。

Its the complete opposite, the naming convention clearly identifies an interface.

For example if you have:

public class Dog : IPet, IMammal
{
    ....

Just from reading it, I can safely assume that IPet and IMammal are probably interfaces.

The .NET CLR allows for single class inheritance. So, if I have a base class..I can only inherit one class from it. Lets change the IPet interface to a base class..our example now becomes

public class Dog : Pet, IMammal
{
    ....

I am inheriting from the Pet class and implementing the IMammal interface.

If we did it what you are suggesting and removed the letter "I" we have this:

public class Dog : Pet, Mammal
{
    ....

Which one is the class I am inheriting from? Which is the interface I am implementing? It gets confusing right? (FYI..you are supposed to put the base class always first, so you could argue that point...but if you are arguing to remove the letter I from prefixing interface names I doubt you follow that practice as well)

As you can see that naming convention easily tells me a lot about my object without me having to investigate further. I can easily see what I am inheriting vs what I am implementing.

浅语花开 2024-07-18 07:51:16

我也喜欢它,因为我可以将其读作“我动词行为”,如“ICanSave”或“IDoDoubleEntry”等......

I also like it cause I can read it as "I verb-behavior" as in "ICanSave" or "IDoDoubleEntry" etc...

无需解释 2024-07-18 07:51:16

我认为 IInterface 命名约定很愚蠢。 这是匈牙利表示法的一个例子,我赞同鄙视匈牙利表示法的思想流派。 如果您的接口只有一个同名的实现,请考虑这可能是代码异味。

不过,我仍然使用它,因为在这种情况下IInterface是微软推荐的,并且“标准胜于更好”。

I think that the IInterface naming convention is silly. It's an example of Hungarian notation, and I subscribe to the school of thought that despises Hungarian notation. If you have an interface with only one implementation that has the same name, consider the possibility that this is a code smell.

However, I still use it, because in this case IInterface is recommended by Microsoft, and "standard is better than better".

毁梦 2024-07-18 07:51:16

为什么这不是语法突出显示的功能而不是匈牙利表示法? 如果区分类和接口如此重要,为什么 IDE 不将引用接口的标识符设置为斜体呢? 我讨厌在字段之前放置“”或“m”,在类之前放置“C”,等等。更糟糕的是,它鼓励程序员编写非常糟糕的 API,例如:

public class List : IList

而不是更合理的 API:

public class LinkedList : List
public class ArrayList : List
public class HashList : List

即使是 .NET普通阶级的作者就落入了这个陷阱。 类名绝不应该是仅删除“I”的接口名称。 类名应始终告诉用户该类与接口的其他可能实现有何不同。 仅出于这个原因,我就投票赞成放弃愚蠢的“我”。

另外,当我使用智能感知时,我想按功能区域对事物进行分组,而不是按类或接口进行分组。 我从不认为“我需要一个接口,而不是一个类”。 我总是想,“我需要一些能做某事的东西”。

Why isn't this a function of syntactical highlighting instead of Hungarian notation? Why doesn't the IDE just italicize identifiers that refer to interfaces if it's so important to distinguish between classes and interfaces. I hate putting "" or "m" before fields, "C" before classes, etc. Even worse, it encourages programmers write really bad APIs such as:

public class List : IList

instead of a more reasonable:

public class LinkedList : List
public class ArrayList : List
public class HashList : List

Even the .NET common class authors fell into this trap. A class name should NEVER be the name of the interface with just the "I" removed. The class name should always tell the user how the class differs from other possible implementations of the interface(s). I vote for dropping the stupid "I" for that reason alone.

Also, when I use intellisense, I want to group things by functional area, not whether it's a class or interface. I never think, "I need an interface, not a class." I always think, "I need something that does X".

我为君王 2024-07-18 07:51:16

实际上,我发现避免命名冲突很有用,例如,我可以创建一个名为 Fred 的具体类来实现 IFred

Actually I find it useful to avoid naming clashes, I might for example create a concrete class called Fred that implements IFred

谜兔 2024-07-18 07:51:16

我一直认为在行为界面中使用动词很有趣。 这与使用名词的类命名约定不同,但它允许类“说话”其行为。

class Dog: IBark

这对于像 WCF 接口这样的结构接口来说效果不太好,但我们不需要一直玩得开心。

要回答您的问题,请将 I 视为“实现”所以...

class DogDataService : Dog, IDataService

此服务类继承自 Dog 并实现 IDataService

我仍然没有真正回答你的问题,但是 I 很有用,因为你会在命名空间、类和接口之间遇到命名冲突。

namespace DataService
interface DataService
class DataService: DataService

所以我们最终得到了

namespace DataServices
interface IDataService
class DataService : IDataService

我认为实际上这是一个理智的约定。

I always thought it was fun to use verbs for behavioral interfaces. This is a departure from the class naming convention of using nouns, but it allows the class to "speak" to its behavior.

class Dog: IBark

This does not work well for structural interfaces like WCF interfaces, but we don't need to have fun all the time.

to answer your question, think of the I as "implements" So...

class DogDataService : Dog, IDataService

this service class inherits from Dog and implements IDataService

I'm still not really answering your question, but the I is useful because you get naming collisions between namespace, class and interface.

namespace DataService
interface DataService
class DataService: DataService

so we end up with

namespace DataServices
interface IDataService
class DataService : IDataService

I think in reality, it's a sanity convention.

时间海 2024-07-18 07:51:16

如果您考虑这两个“最佳实践格言”

清晰度为王

噪音不好

那么它们之间就存在冲突。 问题是:什么时候清晰度会变成噪音?

对我来说,编写 Person person = new PersonImpl() 比编写 IPerson person = new Person() 更嘈杂(但同样清晰)。

If you consider the two "best-practice-aphorisms"

clarity is king

and

noise is bad

there is a conflict between these. The question is: when does clarity become noise?

For me it more noisy (but equally clear) to write Person person = new PersonImpl() than IPerson person = new Person().

走野 2024-07-18 07:51:16

要么就是这样,要么将“Impl”添加到接口的实现中(啊)。 我对“I”没有意见,它是接口最简单、最直接的命名。

It's either that or add "Impl" to the implementation of the interface (argh). I don't have a problem with the "I", it is the simplest and most straightforward naming for an interface.

九局 2024-07-18 07:51:16

“I”约定似乎是一个古老的约定,在今天已经不再适用。 当前的代码编辑器提供了有关您正在使用的类型的大量见解,因此争论“识别接口更容易”就像要求名称空间以“N”为前缀,因为您希望确保不会将其与一个具体的类(前缀为“C”?)。

约定并不意味着这是一个好的约定。 有时,这只是因为人们开始使用它......

以 C# 文档生成器为例:它不关心它......如果你的界面没有前缀“I”,你仍然会在文档的界面部分。 您真的认为在文档的接口部分中为所有接口添加前缀“I”是相关信息并可以帮助您更好地识别接口吗?

The "I" convention seems to be an old convention that wouldn't be relevant today. Current code editor provides lots of insight about the type you are using, so arguing that It's easier to identify the interface is like asking for a namespace to be prefixed by a "N" because you want to be sure that you will not confound it with a concrete class (prefix with a "C"?).

A convention doesn't mean that It's a good convention. Sometimes, It's just because people get to use it...

Take for example the C# documentation generator: It doesn't care about it... if your interface is not prefixed with a "I" you will still see your interface in the interface part of your documentation. Do you really think that having a prefix "I" for all your interfaces inside the interface section of your documentation is a relevant information and help you to better identify interfaces?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文