" using"指令应该在名称空间之内还是之外?
我已经在某些Ccode上运行了StyleCop,并且一直在报告我的using
指令应位于名称空间内。
将" using"指令放在名称空间内部而不是名称空间外部是有技术原因的吗?
解决方案
将其放在名称空间中会使声明在文件的该名称空间中处于本地状态(如果文件中有多个名称空间),但是如果每个文件只有一个名称空间,则它们在外部还是外部都没有太大的区别。在名称空间中。
using ThisNamespace.IsImported.InAllNamespaces.Here; namespace Namespace1 { using ThisNamespace.IsImported.InNamespace1.AndNamespace2; namespace Namespace2 { using ThisNamespace.IsImported.InJustNamespace2; } } namespace Namespace3 { using ThisNamespace.IsImported.InJustNamespace3; }
根据Hanselman使用指令和程序集加载...以及其他此类文章,技术上没有区别。
我的偏好是将它们放在名称空间之外。
两者之间实际上存在(细微)差异。假设我们在File1.cs中具有以下代码:
// File1.cs using System; namespace Outer.Inner { class Foo { static void Bar() { double d = Math.PI; } } }
现在,假设有人将另一个文件(File2.cs)添加到项目中,如下所示:
// File2.cs namespace Outer { class Math { } }
编译器先在名称空间之外查看"使用"指令之前搜索"外部",因此会找到" Outer.Math"而非" System.Math"。不幸的是(或者幸运的是?),Outer.Math没有PI成员,所以File1现在坏了。
如果将" using"放入名称空间声明中,则情况会发生变化,如下所示:
// File1b.cs namespace Outer.Inner { using System; class Foo { static void Bar() { double d = Math.PI; } } }
现在,编译器先搜索" System",然后再搜索" Outer",再找到" System.Math",一切都很好。
有人会说" Math"对于用户定义的类来说可能是个坏名字,因为" System"中已经有一个。这里的重点只是区别,它会影响代码的可维护性。
有趣的是,如果Foo
在命名空间Outer
中而不是Outer.Inner
中会发生什么。在这种情况下,无论File中的" using"位置在哪里,在File2中添加Outer.Math
都会破坏File1. 这意味着编译器在查看任何" using"指令之前先搜索最内层的命名空间。
根据StyleCop文档:
SA1200:在名称空间中使用DirectivesMustBePlacedWith
原因
Cusing指令放置在名称空间元素的外部。
规则说明
当将using指令或者using-alias指令放置在名称空间元素之外时,会发生违反此规则的情况,除非文件不包含任何名称空间元素。
例如,以下代码将导致两次违反此规则。
using System; using Guid = System.Guid; namespace Microsoft.Sample { public class Program { } }
但是,以下代码不会导致任何违反此规则的情况:
namespace Microsoft.Sample { using System; using Guid = System.Guid; public class Program { } }
这段代码可以干净地编译,没有任何编译器错误。但是,尚不清楚正在分配哪个版本的Guid类型。如果将using指令移至名称空间内,如下所示,则会发生编译器错误:
namespace Microsoft.Sample { using Guid = System.Guid; public class Guid { public Guid(string s) { } } public class Program { public static void Main(string[] args) { Guid g = new Guid("hello"); } } }
代码在以下包含Guid g = new Guid(" hello");的行上的编译器错误中失败。
CS0576:命名空间" Microsoft.Sample"包含与别名" Guid"冲突的定义
该代码为System.Guid类型创建了一个名为Guid的别名,并且还创建了自己的名为Guid的类型,并带有匹配的构造函数接口。后来,代码创建了Guid类型的实例。要创建此实例,编译器必须在Guid的两个不同定义之间进行选择。当将using-alias指令放置在namespace元素之外时,编译器将选择在本地名称空间内定义的Guid的本地定义,并完全忽略在namespace之外定义的using-alias指令。不幸的是,在阅读代码时,这并不明显。
但是,当using-alias指令位于名称空间中时,编译器必须在两个不同的,相互冲突的Guid类型之间进行选择,两者都在同一名称空间中定义。这两种类型都提供了匹配的构造函数。编译器无法做出决定,因此会标记编译器错误。
将using-alias指令放置在名称空间之外是一种不好的做法,因为在这种情况下(实际上不知道实际使用的是哪个版本),这可能导致混乱。这可能会导致可能难以诊断的错误。
将using-alias指令放置在namespace元素中可消除这种情况,使之成为错误的来源。
- 多个命名空间
将多个命名空间元素放在单个文件中通常是一个坏主意,但是如果这样做,那么最好将所有using指令放置在每个命名空间元素中,而不是全局地放置在文件顶部。这将严格限制名称空间的范围,也将有助于避免上述行为。
重要的是要注意,当使用放置在名称空间之外的指令编写代码时,在将这些指令移至名称空间内时应格外小心,以确保这不会改变代码的语义。如上所述,将using-alias指令放置在namespace元素中,可使编译器以冲突的方式进行选择,方式是将指令放置在命名空间之外时不会发生。
如何解决违规
要解决违反此规则的问题,请在命名空间元素内移动所有using指令和using-alias指令。