在命名空间内部还是外部使用using?对C#性能的影响

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

世纪之争:在C#命名空间内部还是外部使用using

\n\n

如果你写过C#代码,你一定在评论或Stack Overflow上见过这场争论。一些开发者固执地将using写在namespace内部,另一些则写在外部。每个人都认为自己的做法是唯一正确的。但谁是对的?更重要的是,这会影响你代码的性能吗?

\n\n

让我们一劳永逸地弄清楚这个问题,深入编译器内部,看看你的using指令到底发生了什么。剧透:答案会让你惊讶。

\n\n

using指令到底是什么,为什么需要它们?

\n\n

在深入探讨之前,我们先回顾一下基础知识。using指令是你进入其他命名空间的通行证。没有它们,你每次都必须写出完整的限定名称:

\n\n
System.Console.WriteLine("你好,世界!");\nSystem.Collections.Generic.List<int> numbers = new System.Collections.Generic.List<int>();
\n\n

同意吧,这看起来很糟糕。using指令让代码更简洁、更易读:

\n\n
using System;\nusing System.Collections.Generic;\n\nConsole.WriteLine("你好,世界!");\nList<int> numbers = new List<int>();
\n\n

但把它们放在哪里——这个问题困扰着一代又一代的C#开发者。

\n\n

两大阵营:外部 vs 内部

\n\n

以下是两种做法的样子:

\n\n

方案1:using在namespace外部

\n\n
using System;\nusing System.Collections.Generic;\n\nnamespace MyApp\n{\n    class Program\n    {\n        static void Main()\n        {\n            List<int> list = new List<int>();\n        }\n    }\n}
\n\n

方案2:using在namespace内部

\n\n
namespace MyApp\n{\n    using System;\n    using System.Collections.Generic;\n\n    class Program\n    {\n        static void Main()\n        {\n            List<int> list = new List<int>();\n        }\n    }\n}
\n\n

乍一看,区别只在于缩进。但社区分成了两个不可调和的阵营。让我们分析一下各自的论点。

\n\n

论点1:性能与编译

\n\n

最常见的问题是:using的位置是否影响性能?简短的回答是:不。原因如下。

\n\n

using指令对编译器来说纯粹是语法糖。它们只存在于编译阶段。当你的代码变成IL(中间语言)时,using指令不会留下任何痕迹。编译器只是用它们来解析类型名称,然后将其丢弃。

\n\n

让我们用实践来证明这一点。考虑以下代码:

\n\n
// 文件:Program.cs\nusing System;\nusing System.Collections.Generic;\n\nnamespace MyApp\n{\n    class Program\n    {\n        static void Main()\n        {\n            List<int> list = new List<int>();\n            Console.WriteLine(list.Count);\n        }\n    }\n}
\n\n

编译成IL代码后,你会看到大致如下(已大幅简化):

\n\n
.method private hidebysig static void Main() cil managed\n{\n    .entrypoint\n    .maxstack 1\n    .locals init (\n        [0] class [System.Runtime]System.Collections.Generic.List`1<int32> list\n    )\n    \n    // 创建 List<int>\n    newobj instance void class [System.Runtime]System.Collections.Generic.List`1<int32>::.ctor()\n    stloc.0\n    \n    // 调用 Console.WriteLine\n    ldloc.0\n    callvirt instance int32 class [System.Runtime]System.Collections.Generic.List`1<int32>::get_Count()\n    call void [System.Console]System.Console::WriteLine(int32)\n    \n    ret\n}
\n\n

请注意:在IL代码中,使用的是完整的限定名称(System.Collections.Generic.List`1,

博客

书籍推荐