일부 C# 코드에 대해 StyleCop 을 실행 using
지시문이 네임스페이스 내에 있어야 한다고 계속 보고합니다.
using
지시문을 네임스페이스 외부가 아닌 내부에 넣는 기술적인 이유가 있습니까?
질문자 :benPearce
일부 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
System.Math
대신 Outer.Math
를 찾습니다. 불행히도(또는 다행스럽게도?) Outer.Math
PI
멤버가 없으므로 이제 File1이 손상되었습니다.
다음과 같이 네임스페이스 선언 내부 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.Inner
아닌 Outer
네임스페이스에 있는 경우 어떤 일이 발생하는지 주목하는 것도 흥미롭습니다. 이 경우 Outer.Math
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." 사이에는 필요하지 않습니다.)
끝 맺는 말
using을 네임스페이스 선언 내부 또는 외부에 두든 상관없이 나중에 누군가가 더 높은 우선순위를 가진 네임스페이스 중 하나에 동일한 이름을 가진 새 유형을 추가할 가능성이 항상 있습니다.
또한 중첩된 네임스페이스의 이름이 형식과 같은 경우 문제가 발생할 수 있습니다.
검색 계층이 변경되고 다른 유형이 발견될 수 있기 때문에 사용을 한 위치에서 다른 위치로 이동하는 것은 항상 위험합니다. 따라서 하나의 규칙을 선택하고 고수하여 사용을 변경할 필요가 없습니다.
Visual Studio의 템플릿은 기본적으로 네임스페이스 외부 에 용도를 넣습니다(예: VS가 새 파일에서 새 클래스를 생성하도록 하는 경우).
외부 에서 사용하는 것의 (작은) 장점 중 하나는 전역 특성에 대한 using 지시문을 사용할 수 있다는 것입니다(예 [assembly: System.Runtime.InteropServices.ComVisible(false)]
대신 [assembly: 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 - Using Directive and Assembly Loading... 및 기타 기사에 따르면 기술적으로 차이가 없습니다.
내 선호도는 네임스페이스 외부에 두는 것입니다.
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 지시문이 네임스페이스 요소 외부에 배치되면 컴파일러는 로컬 네임스페이스 내에 정의된 Guid의 로컬 정의를 선택하고 네임스페이스 외부에 정의된 using-alias 지시문을 완전히 무시합니다. 불행히도 이것은 코드를 읽을 때 명확하지 않습니다.
그러나 using-alias 지시문이 네임스페이스 내에 배치되면 컴파일러는 동일한 네임스페이스 내에 정의된 두 가지 서로 다른 충돌하는 Guid 유형 중에서 선택해야 합니다. 이 두 유형 모두 일치하는 생성자를 제공합니다. 컴파일러는 결정을 내릴 수 없으므로 컴파일러 오류에 플래그를 지정합니다.
using-alias 지시문을 네임스페이스 외부에 배치하는 것은 실제로 사용 중인 유형의 버전이 명확하지 않은 이와 같은 상황에서 혼란을 초래할 수 있기 때문에 나쁜 습관입니다. 이는 잠재적으로 진단하기 어려운 버그로 이어질 수 있습니다.
네임스페이스 요소 내에 using-alias 지시문을 배치하면 이를 버그의 원인으로 제거할 수 있습니다.
단일 파일 내에 여러 네임스페이스 요소를 배치하는 것은 일반적으로 나쁜 생각이지만, 이것이 완료되면 모든 using 지시문을 파일의 맨 위에 전역적으로 배치하는 것보다 각 네임스페이스 요소 내에 배치하는 것이 좋습니다. 이것은 네임스페이스의 범위를 엄격하게 지정하고 위에서 설명한 종류의 동작을 피하는 데 도움이 됩니다.
코드가 네임스페이스 외부에 배치된 using 지시문으로 작성된 경우 네임스페이스 내에서 이러한 지시문을 이동할 때 주의를 기울여 코드의 의미를 변경하지 않도록 주의해야 합니다. 위에서 설명한 대로 using-alias 지시문을 네임스페이스 요소 내에 배치하면 지시문이 네임스페이스 외부에 배치될 때 발생하지 않는 방식으로 컴파일러가 충돌하는 유형 중에서 선택할 수 있습니다.
위반을 수정하는 방법 이 규칙 위반을 수정하려면 네임스페이스 요소 내에서 모든 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>>>;
예쁘지 않은.
내가 겪은 한 가지 주름(다른 답변에서는 다루지 않음):
다음과 같은 네임스페이스가 있다고 가정합니다.
namespace Parent
외부 에서 using Something.Other
를 사용하는 경우 첫 번째 것(Something.Other)을 참조합니다.
그러나 해당 네임스페이스 선언 내 에서 사용하는 경우 두 번째 선언(Parent.Something.Other)을 참조합니다!
간단한 해결책이 있습니다: " global::
" 접두사를 추가하세요: docs
namespace Parent { using global::Something.Other; // etc }
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; } }
다른 답변에서 다루지 않은 또 다른 미묘함은 동일한 이름의 클래스와 네임스페이스가 있는 경우입니다.
네임스페이스 내부에 가져오기가 있으면 클래스를 찾습니다. 가져오기가 네임스페이스 외부에 있으면 가져오기가 무시되고 클래스와 네임스페이스가 정규화되어야 합니다.
//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. } } }
기술적인 이유는 답변에서 논의되며 차이가 그렇게 크지 않고 둘 다에 대한 절충점이 있기 때문에 결국 개인 취향에 따른다고 생각합니다. .cs
파일을 만들기 위한 Visual Studio의 기본 템플릿은 네임스페이스 외부의 using
다음을 사용하여 프로젝트 파일의 루트에 stylecop.json
파일을 추가하여 네임스페이스 외부의 지시문을 using
확인하도록 stylecop을 조정할 수 있습니다.
{ "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json", "orderingRules": { "usingDirectivesPlacement": "outsideNamespace" } } }
솔루션 수준에서 이 구성 파일을 생성하고 프로젝트에 '기존 링크 파일'로 추가하여 모든 프로젝트에서도 구성을 공유할 수 있습니다.
Microsoft의 내부 지침을 인용할 때 코딩 경험이 10년 미만인 사람이 작성한 것임을 염두에 두십시오. 다시 말해서, 그들은 개인적인 취향보다 더 확고한 것을 기반으로 할 가능성이 큽니다. 특히 C#과 같은 새로운 분야에서는 더욱 그렇습니다.
일반적으로 외부 using
지시문(예: System 및 Microsoft 네임스페이스)은 namespace
지시문 외부 에 배치해야 합니다. 달리 지정하지 않는 한 모든 경우에 적용해야 하는 기본값입니다. 여기에는 현재 프로젝트의 일부가 아닌 조직의 내부 라이브러리가 포함되거나 동일한 프로젝트의 다른 기본 네임스페이스를 참조 using
현재 프로젝트 및 네임스페이스의 다른 모듈을 참조하는 모든 using
지시문은 namespace
지시문 안에 배치해야 합니다. 이것은 두 가지 특정 기능을 제공합니다.
후자의 이유가 중요합니다. 이는 코드를 리팩토링하는 것보다 중요하지 않은 변경으로 인해 발생할 수 있는 모호한 참조 문제를 도입하는 것이 더 어렵다는 것을 의미합니다. 즉, 한 파일에서 다른 파일로 메소드를 이동하면 갑자기 이전에 없었던 버그가 나타납니다. 구어체로, 'heisenbug' - 역사적으로 추적하기가 매우 어렵습니다.
훨씬 더 일반적인 규칙으로 따라야 할 좋은 규칙은 다음과 같습니다. 쓸모없는 옵션처럼 보이는 언어 고유의 무언가를 본다면 그렇지 않다고 가정하십시오. 사실, 옵션이 존재하는 이유를 알기가 어려울수록 더 중요하다고 가정해야 합니다. 두 옵션 사이의 구체적인 차이점에 대해 조사한 다음 그 의미에 대해 오랫동안 진지하게 생각하십시오. 당신은 일반적으로 언어 디자이너가 당신의 삶을 더 쉽게 만들기 위해 특별히 넣은 모호한 문제에 대한 놀랍도록 통찰력 있고 영리한 해결책을 찾을 수 있을 것입니다. 적절하게 감사하고 활용하십시오.
소스 솔루션에 사용된 " 참조 "를 사용하는 기본값 이 네임스페이스 외부에 있어야 하고 "새로 추가된 참조"인 것이 네임스페이스 내부에 넣어야 하는 것이 좋은 방법인 경우 더 나은 방법입니다. 이것은 어떤 참조가 추가되고 있는지 구별하기 위한 것입니다.
출처 : http:www.stackoverflow.com/questions/125319/should-using-directives-be-inside-or-outside-the-namespace
변수가 '정의되지 않음' 또는 'null'인지 어떻게 확인할 수 있습니까? (0) | 2021.11.29 |
---|---|
디렉토리가 이미 존재하지 않는 경우에만 mkdir하는 방법은 무엇입니까? (0) | 2021.11.29 |
Spring에서 @Component, @Repository & @Service 주석의 차이점은 무엇입니까? (2) | 2021.11.29 |
JavaScript 자르기/슬라이스/문자열의 마지막 문자 자르기 (0) | 2021.11.29 |
Java에서 배열을 어떻게 선언하고 초기화합니까? (0) | 2021.11.29 |