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
{
}
}
컴파일러 는 네임 스페이스 외부 Outer
에서 해당 using
지시문을보기 전에 검색 하므로 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
namespace Outer
가 아니라 namespace에 있으면 어떻게되는지 주목하는 것도 흥미 롭습니다 Outer.Inner
. 이 경우 Outer.Math
File2에 추가 하면 using
이동 위치에 관계없이 File1이 중단 됩니다. 이는 컴파일러가 using
지시문을 보기 전에 가장 안쪽의 네임 스페이스를 검색 함을 의미합니다 .
답변
이 스레드에는 이미 훌륭한 답변이 있지만이 추가 답변으로 조금 더 자세하게 가져올 수 있다고 생각합니다.
먼저 마침표가있는 네임 스페이스 선언은 다음과 같습니다.
namespace MyCorp.TheProduct.SomeModule.Utilities
{
...
}
전적으로 다음과 같습니다.
namespace MyCorp
{
namespace TheProduct
{
namespace SomeModule
{
namespace Utilities
{
...
}
}
}
}
원하는 경우 using
이러한 모든 수준 에 지시문을 둘 수 있습니다. (물론, 우리 using
는 한 곳에만 있기를 원하지만 언어에 따라 합법적입니다.)
어떤 유형이 암시되는지 확인하는 규칙은 다음과 같이 느슨하게 설명 할 수 있습니다. 먼저 일치하는 가장 안쪽의 “범위”를 검색합니다. 아무것도 발견되지 않으면 다음 범위로 한 레벨 이동하여 검색합니다 . 일치하는 것을 찾을 때까지. 어떤 수준에서 두 개 이상의 일치하는 항목이 발견되면 유형 중 하나가 현재 어셈블리에서 온 경우 해당 유형을 선택하고 컴파일러 경고를 발행하십시오. 그렇지 않으면 포기 (컴파일 타임 오류)합니다.
이제 두 가지 주요 규칙이있는 구체적인 예에서 이것이 무엇을 의미하는지 명시 해 보겠습니다.
(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
- 의 유형 널 네임 스페이스 (전역 네임 스페이스)
- 유형에서
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
은 다음 순서로 진행됩니다.
- 내부의 중첩 유형
C
(상속 된 중첩 유형 포함) - 현재 네임 스페이스의 유형
MyCorp.TheProduct.SomeModule.Utilities
- 유형에서
System
,System.Collections.Generic
,System.Linq
,MyCorp.TheProduct
,MyCorp.TheProduct.OtherModule
,MyCorp.TheProduct.OtherModule.Integration
, 및ThirdParty
- 네임 스페이스의 유형
MyCorp.TheProduct.SomeModule
- 유형
MyCorp
- 의 유형 널 네임 스페이스 (전역 네임 스페이스)
( MyCorp.TheProduct
이는 “3.”의 일부이므로 “4.”와 “5.”사이에는 필요하지 않았습니다.)
끝 맺는 말
네임 스페이스 선언 내부 또는 외부에 용도를 사용하더라도 나중에 누군가가 우선 순위가 더 높은 네임 스페이스 중 하나에 동일한 이름의 새 유형을 추가 할 가능성이 항상 있습니다.
또한 중첩 네임 스페이스가 유형과 이름이 같은 경우 문제가 발생할 수 있습니다.
검색 계층 구조가 변경되고 다른 유형이있을 수 있으므로 사용을 한 위치에서 다른 위치로 옮기는 것은 항상 위험합니다. 따라서 하나의 규칙을 선택하고 준수하여 사용을 이동할 필요가 없습니다.
Visual Studio의 템플릿은 기본적으로 용도를 네임 스페이스 외부 에 둡니다 (예 : VS가 새 파일에서 새 클래스를 생성하도록하는 경우).
외부 에서 사용하는 것의 가장 작은 장점은 예를 들어 [assembly: ComVisible(false)]
대신 전역 속성에 대해 using 지시문을 사용할 수 있다는 것입니다 [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 : 네임 스페이스에서 지시문 사용
원인 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");
CS0576 : 네임 스페이스 ‘Microsoft.Sample’에 별칭 ‘Guid’와 충돌하는 정의가 포함되어 있습니다.
이 코드는 Guid라는 System.Guid 형식에 대한 별칭을 만들고 일치하는 생성자 인터페이스를 사용하여 Guid라는 자체 형식을 만듭니다. 나중에이 코드는 Guid 유형의 인스턴스를 만듭니다. 이 인스턴스를 만들려면 컴파일러가 Guid의 두 가지 다른 정의 중에서 선택해야합니다. using-alias 지시문이 namespace 요소 외부에 배치되면 컴파일러는 로컬 네임 스페이스 내에 정의 된 Guid의 로컬 정의를 선택하고 네임 스페이스 외부에 정의 된 using-alias 지시문을 완전히 무시합니다. 불행히도 이것은 코드를 읽을 때 분명하지 않습니다.
그러나 using-alias 지시문이 네임 스페이스 내에 있으면 컴파일러는 동일한 네임 스페이스 내에 정의 된 서로 상충되는 두 가지 Guid 유형 중에서 선택해야합니다. 이 두 유형 모두 일치하는 생성자를 제공합니다. 컴파일러가 결정을 내릴 수 없으므로 컴파일러 오류를 표시합니다.
using-alias 지시문을 네임 스페이스 외부에 배치하면 실제로 사용되는 유형의 버전이 확실하지 않은 상황에서 혼동을 일으킬 수 있으므로 나쁜 습관입니다. 이로 인해 잠재적으로 진단하기 어려운 버그가 발생할 수 있습니다.
네임 스페이스 요소 내에 using-alias 지시문을 배치하면이를 버그의 원인으로 사용할 수 없습니다.
- 여러 네임 스페이스
단일 파일 내에 여러 네임 스페이스 요소를 배치하는 것은 일반적으로 좋지 않은 방법이지만 이것이 완료되면 전역 적으로 파일의 맨 위가 아닌 각 네임 스페이스 요소 내에 모든 사용 지시문을 배치하는 것이 좋습니다. 이렇게하면 네임 스페이스의 범위가 좁아지고 위에서 설명한 동작을 피하는 데 도움이됩니다.
네임 스페이스 외부에있는 지시문을 사용하여 코드를 작성한 경우 네임 스페이스 내에서 이러한 지시문을 이동할 때 코드의 의미가 변경되지 않도록주의해야합니다. 위에서 설명한 바와 같이, 네임 스페이스 요소 내에 using-alias 지시문을 배치하면 컴파일러가 지시문이 네임 스페이스 외부에 배치 될 때 발생하지 않는 방식으로 충돌하는 유형 중에서 선택할 수 있습니다.
위반을 수정하는 방법이 규칙의 위반을 수정하려면 네임 스페이스 요소 내에서 using using 지시문과 using-alias 지시문을 모두 이동하십시오.
답변
별칭을 사용하려는 경우 네임 스페이스 내에 using 문을 배치하는 데 문제가 있습니다. 별명은 이전 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;
}
}