“使用”指令应该位于命名空间的内部还是外部?

我一直在通过一些C#代码运行StyleCop,并且不断报告我的using指令应该位于命名空间内。

using指令放在里面而不是命名空间之外是否有技术原因?


两者之间实际存在着(微妙的)区别。 想象一下你在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
    {
    }
}

编译器在查看名称空间外的那些using指令之前先搜索Outer ,以便找到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指令之前搜索最内层的封闭名称空间。


这个线程已经有了一些很好的答案,但我觉得我可以带来更多的细节与这个额外的答案。

首先,请记住带有句点的名称空间声明,如:

namespace MyCorp.TheProduct.SomeModule.Utilities
{
    ...
}

完全等同于:

namespace MyCorp
{
    namespace TheProduct
    {
        namespace SomeModule
        {
            namespace Utilities
            {
                ...
            }
        }
    }
}

如果你想,你可以在所有这些级别上using指令。 (当然,我们只想在一个地方using s,但根据语言它是合法的。)

解决这种类型隐含的规则可以这样宽松地陈述: 首先搜索最内层的“范围”进行匹配,如果没有发现任何内容,则向下一个范围出去一层并在那里搜索,依此类推 ,直到找到一场比赛。 如果在某个级别找到多个匹配项,如果其中一个类型来自当前程序集,请选择该项并发出编译器警告。 否则,放弃(编译时错误)。

现在让我们明确一下这两个主要公约的具体例子的含义。

(1)外部使用:

using System;
using System.Collections.Generic;
using System.Linq;
//using MyCorp.TheProduct;  <-- uncommenting this would change nothing
using MyCorp.TheProduct.OtherModule;
using MyCorp.TheProduct.OtherModule.Integration;
using ThirdParty;

namespace MyCorp.TheProduct.SomeModule.Utilities
{
    class C
    {
        Ambiguous a;
    }
}

在上面的例子中,为了找出什么类型的Ambiguous ,搜索顺序如下:

  • C嵌套类型(包括继承的嵌套类型)
  • 当前命名空间MyCorp.TheProduct.SomeModule.Utilities类型
  • 命名空间MyCorp.TheProduct.SomeModule类型
  • MyCorp.TheProduct类型
  • MyCorp类型
  • 空名称空间中的类型(全局名称空间)
  • SystemSystem.Collections.GenericSystem.LinqMyCorp.TheProduct.OtherModuleMyCorp.TheProduct.OtherModule.IntegrationThirdParty
  • 另一个约定:

    (2)内部使用:

    namespace MyCorp.TheProduct.SomeModule.Utilities
    {
        using System;
        using System.Collections.Generic;
        using System.Linq;
        using MyCorp.TheProduct;                           // MyCorp can be left out; this using is NOT redundant
        using MyCorp.TheProduct.OtherModule;               // MyCorp.TheProduct can be left out
        using MyCorp.TheProduct.OtherModule.Integration;   // MyCorp.TheProduct can be left out
        using ThirdParty;
    
        class C
        {
            Ambiguous a;
        }
    }
    

    现在,搜索类型Ambiguous按以下顺序进行:

  • C嵌套类型(包括继承的嵌套类型)
  • 当前命名空间MyCorp.TheProduct.SomeModule.Utilities类型
  • 在类型SystemSystem.Collections.GenericSystem.LinqMyCorp.TheProductMyCorp.TheProduct.OtherModuleMyCorp.TheProduct.OtherModule.IntegrationThirdParty
  • 命名空间MyCorp.TheProduct.SomeModule类型
  • MyCorp类型
  • 空名称空间中的类型(全局名称空间)
  • (请注意, MyCorp.TheProduct是“3.”的一部分,因此在“4.”和“5.”之间不需要)。

    结束语

    无论将用途放在名称空间声明的内部还是外部,总会有人有可能在稍后向具有较高优先级的名称空间之一添加一个具有相同名称的新类型。

    另外,如果嵌套名称空间与类型名称相同,则可能会导致问题。

    将使用从一个位置移动到另一个位置是非常危险的,因为搜索层次结构会发生变化,并且可能会找到其他类型。 因此,选择一个约定并坚持下去,这样你就不必移动使用了。

    默认情况下,Visual Studio的模板将使用情况放在命名空间之外(例如,如果您让VS在新文件中生成新类)。

    外部使用的一个(微小)优点是,您可以使用全局属性的using指令,例如[assembly: ComVisible(false)]而不是[assembly: System.Runtime.InteropServices.ComVisible(false)]


    将它放入命名空间中会使该文件的声明局部于该命名空间(如果文件中有多个命名空间),但如果每个文件只有一个命名空间,则无论它们是在外面还是在外面都没有太大区别在命名空间内。

    using ThisNamespace.IsImported.InAllNamespaces.Here;
    
    namespace Namespace1
    { 
       using ThisNamespace.IsImported.InNamespace1.AndNamespace2;
    
       namespace Namespace2
       { 
          using ThisNamespace.IsImported.InJustNamespace2;
       }       
    }
    
    namespace Namespace3
    { 
       using ThisNamespace.IsImported.InJustNamespace3;
    }
    
    链接地址: http://www.djcxy.com/p/3565.html

    上一篇: Should 'using' directives be inside or outside the namespace?

    下一篇: C#.Net case