문제

내가 실행되었습니다 StyleCop 일부는 이상 C#코드,그리고 그것을 유지하는 것을 보고 나 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
    {
    }
}

컴파일러 검색 Outer 그것들을보기 전에 using 네임 스페이스 외부의 지시문이므로 발견됩니다 Outer.Math 대신에 System.Math. 불행히도 (또는 아마도 다행히도?), Outer.Math 없다 PI 멤버, 그래서 파일 1이 깨졌습니다.

당신이 넣으면 이것은 변경됩니다 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. 이 경우 추가 Outer.Math File2에서 위치에 관계없이 파일 1을 끊습니다 using 간다. 이것은 컴파일러가 가장 안쪽으로 둘러싸인 네임 스페이스를 검색하기 전에 검색한다는 것을 의미합니다. using 지령.

다른 팁

이 스레드에는 이미 훌륭한 답변이 있지만이 추가 답변으로 좀 더 자세히 설명 할 수 있다고 생각합니다.

먼저, 다음과 같은 기간이있는 네임 스페이스 선언을 기억하십시오.

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

전적으로 다음과 같습니다.

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

당신이 원한다면, 당신은 넣을 수 있습니다 using 이 모든 수준에 대한 지침. (물론 우리는 갖고 싶어합니다 usingS는 단 한 곳에 있지만 언어에 따라 합법적입니다.)

어떤 유형을 암시하는지 해결하기위한 규칙은 다음과 같이 느슨하게 언급 될 수 있습니다. 먼저 일치에 대한 내부 "스코프"를 검색하십시오., 경기가 발견 될 때까지. 어느 수준에서 둘 이상의 일치가 발견되면, 유형 중 하나가 현재 어셈블리에서 나온 경우 해당 유형을 선택하고 컴파일러 경고를 발행하십시오. 그렇지 않으면 포기 (컴파일 타임 오류).

이제 두 가지 주요 컨벤션과 함께 구체적인 예에서 이것이 무엇을 의미하는지 명확하게합시다.

(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 검색은 다음 순서로 진행됩니다.

  1. 내부 중첩 유형 C (상속 중첩 유형 포함)
  2. 현재 네임 스페이스의 유형 MyCorp.TheProduct.SomeModule.Utilities
  3. 네임 스페이스 유형 MyCorp.TheProduct.SomeModule
  4. 유형 MyCorp.TheProduct
  5. 유형 MyCorp
  6. 유형 없는 네임 스페이스 (글로벌 네임 스페이스)
  7. 유형 System, System.Collections.Generic, System.Linq, MyCorp.TheProduct.OtherModule, MyCorp.TheProduct.OtherModule.Integration, 그리고 ThirdParty

다른 대회 :

(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 이 순서로 간다 :

  1. 내부 중첩 유형 C (상속 중첩 유형 포함)
  2. 현재 네임 스페이스의 유형 MyCorp.TheProduct.SomeModule.Utilities
  3. 유형 System, System.Collections.Generic, System.Linq, MyCorp.TheProduct, MyCorp.TheProduct.OtherModule, MyCorp.TheProduct.OtherModule.Integration, 그리고 ThirdParty
  4. 네임 스페이스 유형 MyCorp.TheProduct.SomeModule
  5. 유형 MyCorp
  6. 유형 없는 네임 스페이스 (글로벌 네임 스페이스)

(그 점에 유의하십시오 MyCorp.TheProduct "3"의 일부였습니다. 그러므로 "4"사이에는 필요하지 않았다. 및 "5.".)

끝 맺는 말

네임 스페이스 선언 내부 또는 외부에 추방을하더라도, 나중에 누군가가 나중에 우선 순위가 높은 네임 스페이스 중 하나에 동일한 이름을 가진 새로운 유형을 추가 할 가능성이 항상 있습니다.

또한 중첩 네임 스페이스가 유형과 동일한 이름을 갖는 경우 문제가 발생할 수 있습니다.

검색 계층 구조가 변경되고 다른 유형을 찾을 수 있으므로 결과를 한 위치에서 다른 위치로 이동하는 것은 항상 위험합니다. 따라서 하나의 컨벤션을 선택하고이를 고수하여 결과를 이동할 필요가 없습니다.

Visual Studio의 템플릿은 기본적으로 밖의 네임 스페이스 중 (예를 들어 VS가 새 파일에서 새 클래스를 생성하는 경우).

사용을위한 하나의 (작은) 장점 밖의 예를 들어 글로벌 속성에 대한 사용 지침을 활용할 수 있다는 것입니다. [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;
}

에 따르면 Hanselman- 지침 및 어셈블리 로딩 사용 ... 그리고 다른 기사들도 기술적으로 차이가 없습니다.

내가 선호하는 것은 네임 스페이스 외부에 놓는 것입니다.

에 따라하 StyleCop 설명서:

SA1200:UsingDirectivesMustBePlacedWithinnamespace

원인 C#지시어를 사용하여 위치한 외부 네임스페이스의 요소입니다.

규칙 설명 이 규칙 위반이 발생할 때 사용하는 지시어는 사용-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 를 입력되는 할당됩니다.는 경우에 사용하는 지시어는 내부 이동의 네임스페이스,아래와 같이 컴파일러 오류가 발생합니다.

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.샘플'에 정의 충돌하는 별칭이'Guid'

코드 별칭을 만듭니다.Guid 라는 형식 Guid 를 만듭니다 또한 그것의 자신의 유형이라고 Guid 와 일치하는 생성자 인터페이스입니다.나중에 코드의 인스턴스를 만듭니다 유형입니다.을 만들이 인스턴스,컴파일러를 선택해야만 하는 두 개의 서로 다른 정의입니다.사용하는 경우-alias 지시어는 외부에 있는 네임스페이스의 요소를 컴파일러를 선택의 로컬 정의 Guid 내에서 정의 로컬 네임스페이스 및 완전히 무시하여-alias 지시어는 정의한 외부의 네임스페이스가 있습니다.이것은,불행하게도,이 명확하지 않을 읽을 때 코드입니다.

할 때 사용하는 alias 지시어에 위치하는 네임스페이스,그러나 컴파일러는 사이에서 선택을했습니다 두 개의 서로 다른 충돌하는 Guid 종류 정의를 모두 동일한 네임스페이스가 있습니다.이 두 가지 유형을 제공이 일치하는 생성자입니다.컴파일러 결정을 내리도록,그래 컴파일러에 오류가 있습니다.

Using-alias 지시어는 외부의 네임스페이스가 나쁜 연습으로 이어질 수 있기 때문에 혼란이 같은 상황에서,그것은 분명하지 않는 버전의 유형은 실제로 사용되고 있습니다.이 잠재적으로 이어질 수 있습니다면 버그가 될 수 있는 진단하기가 어렵습니다.

치를 사용하여-alias 지시어에서 네임스페이스의 요소를 제거로 이것을 소스의 버그가 있습니다.

  1. 여러 네임스페이스

을 배치하는 여러 네임스페이스에서 요소의 단일 파일은 일반적으로는 나쁜 생각하지만,경과할 때 이를 수행,그것은 좋은 생각을 사용하여 모든 지시어에서 각각의 네임스페이스의 요소보다는 전 세계적으로 상단의 파일입니다.이 범위는 네임스페이스 단단히하고 또한 도움을 피하는 종류의 동작을 설명한다.

그것이 중요할 경우에는 코드는 지시어를 사용하여 외부로 배치의 네임스페이스,주의해야 합로 이동할 때는 이 지시어가 내의 네임스페이스를 보장하는 것 이것은 변경되지 않는 의미의 코드입니다.위에서 설명한 바와 같이,배치 사용-alias 지시어에서 네임스페이스의 요소를 사용하면 컴파일러 사이의 선택 유형 충돌하는 방법으로는 일어나지 않을 것이면 이 지시어는 외부에 배치의 네임스페이스가 있습니다.

위반 문제를 해결하는 방법 를 해결하 이 규칙의 위반,이동 모든 지시어를 사용하여 사용-alias 지시어에서 네임스페이스의 요소입니다.

별명을 사용하려면 네임 스페이스 내부에 명령문을 사용하는 데 문제가 있습니다. 별칭은 이전의 혜택을받지 않습니다 using 진술은 자격을 갖추어야합니다.

고려하다:

namespace MyNamespace
{
    using System;
    using MyAlias = System.DateTime;

    class MyClass
    {
    }
}

대:

using System;

namespace MyNamespace
{
    using MyAlias = DateTime;

    class MyClass
    {
    }
}

다음과 같은 길이의 별명이있는 경우 (문제를 발견 한 방법) : 이는 특히 두드러 질 수 있습니다.

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>>>;

예쁘지 않은.

Jeppe Stig Nielsen으로 말했다,이 스레드는 이미 큰 대답을 가지고 있지만,이 명백한 미묘함도 언급 할 가치가 있다고 생각했습니다.

using 내부 네임 스페이스에 지정된 지침은 외부에 지정된 시점과 같이 완전히 자격을 갖추지 않아도되므로 더 짧은 코드를 만들 수 있습니다.

다음 예제는 유형이기 때문에 작동합니다 Foo 그리고 Bar 둘 다 동일한 글로벌 네임 스페이스에 있으며 Outer.

코드 파일을 추정합니다 foo.cs:

namespace Outer.Inner
{
    class Foo { }
}

그리고 bar.cs:

namespace Outer
{
    using Outer.Inner;

    class Bar
    {
        public Foo foo;
    }
}

그것은 외부 네임 스페이스를 생략 할 수 있습니다 using 지침, 짧은 :

namespace Outer
{
    using Inner;

    class Bar
    {
        public Foo foo;
    }
}

하나의 주름이 내가 달려 갔다 (다른 답변으로 덮여 있지 않음) :

이 네임 스페이스가 있다고 가정합니다.

  • 뭔가. 다른
  • parent.something.other

당신이 사용할 때 using Something.Other 밖의 a namespace Parent, 그것은 첫 번째 (무언가. 다른)를 나타냅니다.

그러나 당신이 그것을 사용하는 경우 내부에 해당 네임 스페이스 선언의 경우 두 번째 선언을 말합니다 (Parent.Something.other)!

간단한 해결책이 있습니다.global::"접두사 : 문서

namespace Parent
{
   using global::Something.Other;
   // etc
}

내가 믿지 않는 또 다른 미묘함은 다른 답변에 의해 다루어 졌다고 생각합니다. 같은 이름의 클래스와 네임 스페이스가있을 때입니다.

네임 스페이스 안에 가져 오면 클래스가 찾을 수 있습니다. 가져 오기가 네임 스페이스 외부에 있으면 가져 오기가 무시되고 클래스와 네임 스페이스가 완전히 자격을 갖추어야합니다.

//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.
        }
    }
}

기술적 인 이유는 답변에서 논의되며 차이가 그렇지 않기 때문에 결국 개인 취향에 따른다고 생각합니다. 그리고 둘 다를위한 트레이드 오프가 있습니다. 생성을위한 Visual Studio의 기본 템플릿 .cs 파일 사용 using 네임 스페이스 외부의 지침 예를 들어

스타일을 조정하여 확인할 수 있습니다 using 추가를 통한 네임 스페이스 외부의 지침 stylecop.json 프로젝트 파일의 루트에있는 파일은 다음과 같습니다.

{
  "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
    "orderingRules": {
      "usingDirectivesPlacement": "outsideNamespace"
    }
  }
}

솔루션 수준 에서이 구성 파일을 작성하고 프로젝트에 '기존 링크 파일'으로 추가하여 모든 프로젝트에서 구성을 공유 할 수 있습니다.

그것들이 있다면 더 나은 연습입니다 기본 IE 사용참조"소스 솔루션에 사용 된 솔루션에서는 네임 스페이스 외부와 "새로운 추가 참조" 모범 사례는 네임 스페이스 안에 넣어야한다는 것입니다. 이것은 참고 문헌이 추가되는 것을 구별하기위한 것입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top