해''사용하는 지시어는 내부 또는 외부 네임스페이스?
-
02-07-2019 - |
문제
내가 실행되었습니다 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
이 모든 수준에 대한 지침. (물론 우리는 갖고 싶어합니다 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
- 유형 없는 네임 스페이스 (글로벌 네임 스페이스)
- 유형
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)]
대신에 [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 지시어에서 네임스페이스의 요소를 제거로 이것을 소스의 버그가 있습니다.
- 여러 네임스페이스
을 배치하는 여러 네임스페이스에서 요소의 단일 파일은 일반적으로는 나쁜 생각하지만,경과할 때 이를 수행,그것은 좋은 생각을 사용하여 모든 지시어에서 각각의 네임스페이스의 요소보다는 전 세계적으로 상단의 파일입니다.이 범위는 네임스페이스 단단히하고 또한 도움을 피하는 종류의 동작을 설명한다.
그것이 중요할 경우에는 코드는 지시어를 사용하여 외부로 배치의 네임스페이스,주의해야 합로 이동할 때는 이 지시어가 내의 네임스페이스를 보장하는 것 이것은 변경되지 않는 의미의 코드입니다.위에서 설명한 바와 같이,배치 사용-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 사용참조"소스 솔루션에 사용 된 솔루션에서는 네임 스페이스 외부와 "새로운 추가 참조" 모범 사례는 네임 스페이스 안에 넣어야한다는 것입니다. 이것은 참고 문헌이 추가되는 것을 구별하기위한 것입니다.