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

Why is "using System;" not considered bad practice?

提问人:sebrockm 提问时间:2/4/2020 最后编辑:sebrockm 更新时间:2/5/2020 访问量:5500

问:

我有C++背景,我完全理解并同意这个问题的答案:为什么“使用命名空间std;”被认为是不好的做法?

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

现在,我确实明白在 C# 和 C++ 中使用指令并不完全是一回事。另外,我确实知道,您可以在 C++ 中做的最讨厌的事情之一,即将其放在头文件中,由于缺乏头文件的概念,因此在 C# 中没有同样令人讨厌的对应项。using namespace#include

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

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

我有一些关于答案的想法(不过,这些都没有真正让我满意):

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

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

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

C# C++ 使用指令

评论

2赞 Konrad Rudolph 2/4/2020
@Timo OP 明确询问标题污染。
1赞 Wyck 2/4/2020
我认为这是因为全局命名空间没有像 C++ 那样的竞争(主要是由于 C 标准库)。但我等待那些最了解的人的答案。
2赞 sebrockm 2/4/2020
@ThomasWeller 在C++,这是显而易见的。在 C# 中,考虑一个扩展方法,该方法被称为 via 。如果随后添加另一个包含扩展方法的命名空间,则将改为调用该命名空间。但我还不是 C# 专家。Ext(this T t, long l)t.Ext(0)Ext(this T t, int i)
2赞 sebrockm 2/4/2020
@Franck即使我同意了这一点,同样的论点也适用于C++,这进一步推动了我没有看到 C++ 和 C 之间区别的问题#
3赞 Timo 2/4/2020
如果出现歧义,@Franck C++会向您抛出编译器错误。以及 C#。

答:

-2赞 Asteroids With Wings 2/4/2020 #1

但是,尽管存在差异,但在 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

所以不要比较它们!

评论

2赞 Konrad Rudolph 2/4/2020
这并不能回答 OP 的担忧,这显然不是关于在标头中打开命名空间,而是在实现文件中打开命名空间。
2赞 Asteroids With Wings 2/4/2020
@KonradRudolph C++中要避免的建议主要是关于头文件。答案这不适用于 C#。using namespace std
9赞 Tommy Andersen 2/4/2020
@AsteroidsWithWings要避免的建议当然不是主要关于标题。在标头中使用它很危险。建议不要在您的实现中使用它。using namespace std
1赞 Tommy Andersen 2/4/2020
在 C++ 中要避免的建议是关于避免命名冲突,C# 中的指令也引入了命名冲突的可能性,那么为什么不避免它呢?即使实现不同。using namespace ...using
0赞 AKornich 2/5/2020
@TommyAndersen,如果发生这种冲突,解决这种冲突有多难?这需要一秒钟。由于 C# 声明是每个定义单个类型/类的文件,并且该类型通常与一组相对狭窄的应用程序域概念(理想情况下是单一责任原则)有关,因此此类命名空间冲突的可能性极低。但是当发生时很容易解决。常见的 .NET 开发工具/IDE 对此有很大帮助。考虑整个开发生态系统,该生态系统旨在通过结合多个开发活动的优点来提高工作效率using
35赞 eerorika 2/4/2020 #2

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

“使用系统”并不是普遍不被认为是一种不好的做法。例如,请参阅:为什么在 C# 中不使用“using”指令?

但它可能确实被认为没有 .可能是因为:using namespace std

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

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

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

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

由于这些差异,“using System;”出现名称冲突的几率低于 。using namespace std


此外,命名空间“导入”在某种程度上是一种自我延续的约定:如果导入标准命名空间是约定俗成的,那么程序员通常会尽量避免从该命名空间中选择名称作为他们自己的标识符,这有助于减少这种约定的问题。

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

评论

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