我一直在经过某些C#代码运行StyleCop ,而且一直在报告个人using
指令应该在名称空间内。 函数
是否有技术上的理由将using
指令放在名称空间的内部而不是外部? ui
将其放在名称空间中会使声明在文件的该名称空间中处于本地状态(若是文件中有多个名称空间),可是若是每一个文件只有一个名称空间,则它们在外部仍是外部都不会有太大的区别。在名称空间中。 spa
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-使用指令和程序集加载...以及其余此类文章,技术上没有区别。 code
个人偏好是将它们放在名称空间以外。 blog
当您但愿使用别名时,在名称空间中放置using语句存在问题。 别名不能从较早的using
语句中受益,必须彻底限定。 接口
考虑: ip
namespace MyNamespace { using System; using MyAlias = System.DateTime; class MyClass { } }
与: 文档
using System; namespace MyNamespace { using MyAlias = DateTime; class MyClass { } }
若是您有一个冗长的别名,例如如下内容(这就是我发现问题的方式),则这一点尤为明显: get
using MyAlias = Tuple<Expression<Func<DateTime, object>>, Expression<Func<TimeSpan, object>>>;
在名称空间内using
语句时,它忽然变成: 编译器
using MyAlias = System.Tuple<System.Linq.Expressions.Expression<System.Func<System.DateTime, object>>, System.Linq.Expressions.Expression<System.Func<System.TimeSpan, object>>>;
不漂亮。
根据StyleCop文档:
SA1200:在名称空间中使用DirectivesMustBePlacedWith
缘由AC#using指令放置在名称空间元素以外。
规则说明当将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");
的行中发现如下编译器错误时失败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指令能够消除这种状况,使之成为错误的来源。
将多个名称空间元素放在一个文件中一般是一个坏主意,可是若是这样作,那么最好将全部using指令放在每一个名称空间元素中,而不是全局地放在文件顶部。 这将严格限制名称空间的范围,也将有助于避免上述行为。
重要的是要注意,当使用放置在名称空间以外的指令编写代码时,在将这些指令移至名称空间内时应格外当心,以确保这不会改变代码的语义。 如上所述,将using-alias指令放置在namespace元素中,可以使编译器以冲突的方式进行选择,方式是将指令放在命名空间以外时不会发生。
如何解决冲突要解决违反此规则的问题,请在命名空间元素内移动全部using指令和using-alias指令。
二者之间实际上存在(细微)差别。 假设您在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
而后再using
命名空间以外的指令查看它们,所以它将找到Outer.Math
而不是System.Math
。 不幸的是(或者幸运的是?), Outer.Math
没有PI
成员,所以Outer.Math
如今已损坏。
若是将using
放在名称空间声明中,则状况会发生变化,以下所示:
// File1b.cs namespace Outer.Inner { using System; class Foo { static void Bar() { double d = Math.PI; } } }
如今,编译器在搜索Outer
以前先搜索System
而后找到System.Math
,一切都很好。
有人会认为Math
对于用户定义的类来讲多是个坏名字,由于System
已经有一个了。 这里要说的就是这样是有区别的,它会影响你的代码的可维护性。
有趣的是,若是Foo
在命名空间Outer
而不是Outer.Inner
,会发生什么。 在这种状况下,不管using
在何处,在Outer.Math
中添加Outer.Math
破坏Outer.Math
。 这意味着编译器在查看任何using
指令以前先搜索最里面的命名空间。