世纪之争:在C#命名空间内部还是外部使用using
\n\n如果你写过C#代码,你一定在评论或Stack Overflow上见过这场争论。一些开发者固执地将using写在namespace内部,另一些则写在外部。每个人都认为自己的做法是唯一正确的。但谁是对的?更重要的是,这会影响你代码的性能吗?
让我们一劳永逸地弄清楚这个问题,深入编译器内部,看看你的using指令到底发生了什么。剧透:答案会让你惊讶。
using指令到底是什么,为什么需要它们?
\n\n在深入探讨之前,我们先回顾一下基础知识。using指令是你进入其他命名空间的通行证。没有它们,你每次都必须写出完整的限定名称:
System.Console.WriteLine("你好,世界!");\nSystem.Collections.Generic.List<int> numbers = new System.Collections.Generic.List<int>();\n\n同意吧,这看起来很糟糕。using指令让代码更简洁、更易读:
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\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 }\n }\n}\n\n方案2:using在namespace内部
\n\nnamespace 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的位置是否影响性能?简短的回答是:不。原因如下。
using指令对编译器来说纯粹是语法糖。它们只存在于编译阶段。当你的代码变成IL(中间语言)时,using指令不会留下任何痕迹。编译器只是用它们来解析类型名称,然后将其丢弃。
让我们用实践来证明这一点。考虑以下代码:
\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,