【问题标题】:Why is "using System;" not considered bad practice?为什么是“使用系统”;不被认为是不好的做法?
【发布时间】:2020-05-19 10:08:42
【问题描述】:

我有 C++ 背景,我完全理解并同意这个问题的答案:Why is “using namespace std;” considered bad practice?

所以我很惊讶,现在有了一些 C# 经验,我看到了完全相反的情况: using Some.Namespace; 字面上到处都在使用。每当你开始使用一个类型时,你首先为它的命名空间添加一个 using 指令(如果它还没有的话)。我不记得曾经看过不是以using System; using System.Collections.Generic; using X.Y.Z; etc... 开头的.cs 文件。 事实上,如果您通过 Visual Studio 向导添加一个新文件,它会自动在其中添加一些 using 指令,即使您可能根本不需要它们。因此,虽然在 C++ 社区中你基本上会被处以私刑,但 C# 甚至鼓励这样做。至少在我看来是这样的。

现在,我明白在 C# 和 C++ 中使用指令并不完全相同。另外,我确实理解在 C++ 中使用 using namespace 可以做的最讨厌的事情之一,即把它放在头文件中,由于缺少头文件和 #include 的概念,在 C# 中没有同等讨厌的对应物.

但是,尽管存在差异,但在 C# 和 C++ 中使用指令的目的相同,即只需一直键入 SomeType,而不是更长的 Some.Namespace.SomeType(在 C++ 中使用 :: 而不是.)。出于同样的目的,对我来说危险似乎也是一样的:命名冲突。

在最好的情况下,这会导致编译错误,因此您“只需”修复它。在最坏的情况下,它仍然可以编译,并且代码会默默地执行与您预期不同的事情。所以我的问题是:为什么(显然)使用在 C# 和 C++ 中被认为非常糟糕的指令?

我对答案的一些想法(不过,这些想法都不能让我真正满意):

  • 命名空间在 C# 中往往比在 C++ 中更长且嵌套更多(stdSystem.Collection.Generic)。因此,以这种方式对代码进行去噪有更多的愿望和更多的收获。但即使这是真的,这个论点也只适用于我们查看标准命名空间时。在 C# 和 C++ 中,自定义名称可以使用任何您喜欢的短名称。

  • 命名空间在 C# 中似乎比在 C++ 中更“细粒度”。例如,在 C++ 中,整个标准库包含在 std 中(加上一些小的嵌套命名空间,如 chrono),而在 C# 中,您有 System.IOSystem.ThreadingSystem.Text 等。所以,风险命名冲突较小。然而,这只是一种直觉。我实际上并没有计算你用using namespace stdusing System“导入”了多少个名字。同样,即使这是真的,这个论点也只适用于标准命名空间。您可以根据自己的意愿在 C# 和 C++ 中将您自己的设计设计为细粒度。

还有更多的论据吗?我对真实的事实(如果有的话)特别感兴趣,而不是意见。

【问题讨论】:

  • @Timo OP 明确询问标头污染问题。
  • 我认为这是因为全局命名空间没有与 C++ 相同程度的竞争(主要是由于 C 标准库)。但我等待最了解的人的答案。
  • @ThomasWeller 在 C++ 中很明显。在 C# 中,考虑通过 t.Ext(0) 调用的带有 Ext(this T t, long l) 的扩展方法。如果您随后添加另一个包含扩展方法Ext(this T t, int i) 的命名空间,则会调用该命名空间。但我还不是 C# 方面的专家。
  • @Franck 即使我同意你这一点,那么同样的论点也适用于 C++,进一步推动了我看不到 C++ 和 C# 之间区别的问题
  • @Franck C++ 会在出现歧义时向您抛出编译器错误。以及 C#。

标签: c# c++ using-directives


【解决方案1】:

为什么是“使用系统;”不被认为是不好的做法?

"使用系统;" 普遍不被认为是一种不好的做法。例如:Why would you not use the 'using' directive in C#?

但它可能不像using namespace std 那样被认为糟糕。可能是因为:

  1. C# 没有头文件。使用预处理器将一个 C# 源文件“包含”到另一个 C# 源文件是不常见的。

  2. std 命名空间几乎是扁平的,即几乎所有标准库函数、类型和变量都在其中(很少有例外,例如文件系统子命名空间)。它包含非常非常多的标识符。据我了解,System 包含的名称要少得多,而是包含更多的子命名空间。

  3. 在 C# 中,没有全局函数或变量。因此,与确实有这些的 C++ 相比,全局标识符的数量通常非常少:此外,通常使用没有命名空间的 C 库(通常是间接的),因此将它们的所有名称放入全局命名空间。

  4. 据我所知,C# 没有依赖于参数的查找。 ADL 与名称隐藏、重载等相结合可能会产生一些程序不受名称冲突影响的情况,而另一些则受到轻微影响,并且通过测试捕获所有极端情况是不可行的。

由于这些差异,“使用 System;”名称冲突的可能性低于using namespace std


此外,命名空间“导入”在某种程度上是一种自我延续的约定:如果按照惯例导入标准命名空间,那么程序员将按照惯例尝试避免从该命名空间中选择名称他们自己的标识符,这有助于减少这种约定的问题。

如果这种导入被认为是一种不好的做法,那么程序员甚至不太可能尝试避免与导入的命名空间发生冲突。因此,即使选择之间的争论的权重最初是微妙的,惯例也会倾向于支持或反对这种做法。

【讨论】:

  • 这仅考虑了打开命名空间的潜在缺点。这是一个开始,但我认为我们还需要考虑优势:在 C++ 的情况下,在大多数情况下它可以节省五个字符 (std::)。在 C# 中,它要多得多(System.“只有”7 个字符,但其他嵌套命名空间有 很多 个字符,将它们写在任何地方都会使代码完全不可读)。
  • C# 重载解析是否比 C++ 中的重载解析更友好,并且通过编译器错误引出了很多歧义? (绝不是批评您的回答似乎具有权威性。)
  • @KonradRudolph 如果缺点被认为是显着的,并且打字量同样如此(与打字量std::相比),那么使用using Sys = System;而不是命名空间污染不是典型的风格非别名using?
  • @Bathsheba 关于“权威”,我想声明我对 C# 知之甚少,我的回答是基于 C++ 的知识,以及一些关于 C# 的谷歌搜索。所以,如果有人对 C# 部分进行事实检查,我将不胜感激:)
  • 关于 ADL 部分:C# 有扩展方法。这是与 ADL 不同的设计,但它们在命名冲突方面存在相同的问题。
【解决方案2】:

但是,尽管存在差异,但在 C# 和 C++ 中使用指令具有相同的目的,即只需始终键入 SomeType,而不是更长的 Some.Namespace.SomeType(在 C++ 中使用 :: 而不是 . )。出于同样的目的,对我来说似乎也有危险:命名冲突。

是的,但你没有导出那种危险(阅读:强迫他人处理它),因为:

现在,我明白在 C# 和 C++ 中使用指令并不完全相同。另外,我确实理解在 C++ 中使用命名空间可以做的最讨厌的事情之一,即将它放在头文件中,由于缺乏头文件和#include 的概念,在 C# 中没有等效项。

所以这是一个不同的类别。

此外,C++ 并非像 C# 那样“设计”为在 IDE 中开发。 C# 基本上总是用 Visual Studio 和它的 Intellisense 编写的。它被设计为由创建它的人以这种方式使用。无论有多少人使用 IDE 使用 C++ 进行开发,它的设计都不会将该用例作为压倒性的关注点。

命名空间在 C# 中似乎比在 C++ 中更“细粒度”。

是的,也是。 using namespace stdusing System.Collection.Generic 是没法比的。

所以不要比较它们!

【讨论】:

  • 这并没有回答 OP 的问题,这明确不是关于在标头中打开命名空间,而是在实现文件中。
  • @KonradRudolph 在 C++ 中避免使用using namespace std 的建议主要是关于头文件。答案这不适用于C#。
  • @AsteroidsWithWings 避免使用using namespace std 的建议当然不是关于标题。在标题中使用它是危险的。建议不要在您的实现中使用它。
  • c++中避免using namespace ...的建议是避免命名冲突,C#中的using指令也引入了命名冲突的可能性,那为什么不避免呢?尽管实现方式不同。
  • @TommyAndersen,如果发生这种冲突,解决这种冲突有多难?需要一秒钟。由于 C# using 声明是针对定义单个类型/类的每个文件,并且该类型通常与一组相对狭窄的应用程序域概念(理想情况下,单一职责原则)有关,因此此类命名空间冲突的可能性极低。但是当发生时很容易修复。通用的 .NET 开发工具/IDE 在这方面为您提供了很多帮助。考虑整个开发生态系统,该生态系统旨在通过结合多种开发活动中的精华来提高您的工作效率
猜你喜欢
  • 2010-11-04
  • 2010-10-22
  • 2011-11-20
  • 2022-07-05
  • 1970-01-01
相关资源
最近更新 更多