Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/272.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 应该';使用';指令是在名称空间内还是在名称空间外?_C#_.net_Namespaces_Stylecop_Code Organization - Fatal编程技术网

C# 应该';使用';指令是在名称空间内还是在名称空间外?

C# 应该';使用';指令是在名称空间内还是在名称空间外?,c#,.net,namespaces,stylecop,code-organization,C#,.net,Namespaces,Stylecop,Code Organization,我一直在运行一些C#代码,它不断报告我的using指令应该在名称空间中 using ThisNamespace.IsImported.InAllNamespaces.Here; namespace Namespace1 { using ThisNamespace.IsImported.InNamespace1.AndNamespace2; namespace Namespace2 { using ThisNamespace.IsImported.InJust

我一直在运行一些C#代码,它不断报告我的
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;
}

使用指令将
放在名称空间内部而不是外部是否有技术原因?

将其放在名称空间内部会使文件的声明位于该名称空间的本地(如果文件中有多个名称空间)但是,如果每个文件只有一个名称空间,那么它们是在名称空间外部还是在名称空间内部都没有多大区别

using ThisNamespace.IsImported.InAllNamespaces.Here;

namespace Namespace1
{ 
   using ThisNamespace.IsImported.InNamespace1.AndNamespace2;

   namespace Namespace2
   { 
      using ThisNamespace.IsImported.InJustNamespace2;
   }       
}

namespace Namespace3
{ 
   using ThisNamespace.IsImported.InJustNamespace3;
}
根据和其他类似的文章,在技术上没有区别

我倾向于将它们放在名称空间之外。

两者之间实际上有(细微的)区别。假设您在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
,然后再使用命名空间外的
指令查看这些
,因此它会查找
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;
        }
    }
}
现在,编译器在搜索
外部
之前搜索
系统
,找到
系统.Math
,一切正常

有些人会争辩说,对于用户定义的类来说,
Math
可能是个坏名字,因为在
系统中已经有了一个;这里的要点是有区别,它会影响代码的可维护性


如果
Foo
位于名称空间
Outer
中,而不是
Outer.Inner
中,那么会发生什么,这也很有趣。在这种情况下,在File2中添加
Outer.Math
会中断File1,而不管使用
在哪里。这意味着编译器在使用
指令查看任何
之前搜索最里面的封闭名称空间。

根据StyleCop文档:

SA1200:使用方向必须放置在中间空间中

原因 C#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”)的行中发现以下编译器错误,代码失败

CS0576:命名空间“Microsoft.Sample”包含与别名“Guid”冲突的定义

该代码为System.Guid类型创建了一个名为Guid的别名,还创建了自己的名为Guid的类型,该类型具有匹配的构造函数接口。稍后,代码将创建Guid类型的实例。要创建此实例,编译器必须在两种不同的Guid定义之间进行选择。当using alias指令位于namespace元素之外时,编译器将选择在本地命名空间内定义的Guid的本地定义,并完全忽略在命名空间之外定义的using alias指令。不幸的是,这在阅读代码时并不明显

但是,当using alias指令位于命名空间中时,编译器必须在同一命名空间中定义的两种不同、冲突的Guid类型之间进行选择。这两种类型都提供了匹配的构造函数。编译器无法做出决定,因此它会标记编译器错误

将using alias指令放在名称空间之外是一种不好的做法,因为在这样的情况下,它可能会导致混淆,因为不清楚实际使用的是类型的哪个版本。这可能会导致难以诊断的错误

在namespace元素中使用alias指令可以消除这一缺陷

  • 多名称空间
  • 在一个文件中放置多个名称空间元素通常是一个坏主意,但是如果这样做了,那么最好将所有using指令放置在每个名称空间元素中,而不是全局放置在文件的顶部。这将严格限定名称空间的范围,并有助于避免上述行为

    需要注意的是,当使用放置在名称空间之外的指令编写代码时,在名称空间内移动这些指令时应小心,以确保这不会改变代码的语义。如上所述,在namespace元素中放置usingalias指令允许编译器在冲突类型之间进行选择,这种选择在将指令放置在namespace之外时不会发生

    using ThisNamespace.IsImported.InAllNamespaces.Here;
    
    namespace Namespace1
    { 
       using ThisNamespace.IsImported.InNamespace1.AndNamespace2;
    
       namespace Namespace2
       { 
          using ThisNamespace.IsImported.InJustNamespace2;
       }       
    }
    
    namespace Namespace3
    { 
       using ThisNamespace.IsImported.InJustNamespace3;
    }
    
    如何纠正违规行为
    若要修复违反此规则的情况,请在命名空间元素中移动所有using指令和using alias指令。

    如果要使用别名,请在命名空间中放置using语句。别名不能从前面的
    using
    语句中获益,必须完全限定

    //file1.cs
    namespace Foo
    {
        class Foo
        {
        }
    }
    
    //file2.cs
    namespace ConsoleApp3
    {
        using Foo;
        class Program
        {
            static void Main(string[] args)
            {
                //This will allow you to use the class
                Foo test = new Foo();
            }
        }
    }
    
    //file2.cs
    using Foo; //Unused and redundant    
    namespace Bar
    {
        class Bar
        {
            Bar()
            {
                Foo.Foo test = new Foo.Foo();
                Foo test = new Foo(); //will give you an error that a namespace is being used like a class.
            }
        }
    }
    
    考虑:

    namespace MyNamespace
    {
        using System;
        using MyAlias = System.DateTime;
    
        class MyClass
        {
        }
    }
    
    与:

    using System;
    
    namespace MyNamespace
    {
        using MyAlias = DateTime;
    
        class MyClass
        {
        }
    }
    
    如果您有一个冗长的别名,例如下面这样的别名(这就是我发现问题的原因):


    不太好看。

    这篇文章已经有了一些很好的答案,但我觉得我可以提供更多细节
    namespace MyCorp
    {
        namespace TheProduct
        {
            namespace SomeModule
            {
                namespace Utilities
                {
                    ...
                }
            }
        }
    }
    
    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;
        }
    }
    
    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;
        }
    }
    
    namespace Outer.Inner
    {
        class Foo { }
    }
    
    namespace Outer
    {
        using Outer.Inner;
    
        class Bar
        {
            public Foo foo;
        }
    }
    
    namespace Outer
    {
        using Inner;
    
        class Bar
        {
            public Foo foo;
        }
    }
    
    {
      "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
        "orderingRules": {
          "usingDirectivesPlacement": "outsideNamespace"
        }
      }
    }
    
    //file1.cs
    namespace Foo
    {
        class Foo
        {
        }
    }
    
    //file2.cs
    namespace ConsoleApp3
    {
        using Foo;
        class Program
        {
            static void Main(string[] args)
            {
                //This will allow you to use the class
                Foo test = new Foo();
            }
        }
    }
    
    //file2.cs
    using Foo; //Unused and redundant    
    namespace Bar
    {
        class Bar
        {
            Bar()
            {
                Foo.Foo test = new Foo.Foo();
                Foo test = new Foo(); //will give you an error that a namespace is being used like a class.
            }
        }
    }
    
    namespace Parent
    {
       using global::Something.Other;
       // etc
    }