.NET 모듈이 네임 스페이스와 모듈 파일 이름을 분리하는 이유는 무엇입니까?


9

Scheme 프로그래밍 언어 (R6RS 표준)의 구현에서 다음과 같이 모듈을 가져올 수 있습니다.

(import (abc def xyz))

이 시스템은 파일을 찾을 것을 시도 할 것이다 당신이 당신의 계획 모듈을 유지하는 일부 디렉토리입니다. 모듈의 소스 코드이며 필요한 경우 즉시 컴파일됩니다.$DIR/abc/def/xyz.sls$DIRxyz.sls

Ruby, Python 및 Perl 모듈 시스템은 이와 관련하여 유사합니다.

반면에 C #은 조금 더 복잡합니다.

먼저, 프로젝트별로 참조해야하는 dll 파일이 있습니다. 각각을 명시 적으로 참조해야합니다. 이것은 디렉토리에 dll 파일을 삭제하고 C #을 사용하여 이름으로 선택하는 것보다 더 복잡합니다.

둘째, dll 파일 이름과 dll이 제공하는 네임 스페이스간에 일대일 이름 지정 통신이 없습니다. 이 유연성을 높이 평가할 수 있지만 손을 get 수도 있습니다.

이 구체적으로 말하면 using abc.def.xyz;, C #이 C #이 찾고있는 abc/def/xyz.dll디렉토리 (프로젝트별로 구성 가능)에서 파일을 찾으려고하면 좋을 것 입니다.

모듈을 처리하는 Ruby, Python, Perl, Scheme 방식이 더 우아하다는 것을 알았습니다. 떠오르는 언어는 더 단순한 디자인을 사용하는 경향이 있습니다.

.NET / C # 세상이 왜 이런 식으로 일을합니까?


10
.NET의 어셈블리 및 클래스 확인 메커니즘은 10 년 넘게 제대로 작동했습니다. 바인드 타임에 어셈블리 리다이렉션 등을 지원하고 다른 많은 유용한 해결 메커니즘을 지원하는 것과 같은 방식으로 설계된 이유에 대한 근본적인 오해가 없거나 충분한 연구가 부족하다고 생각합니다.
Kev

using 문에서 DLL을 확인하면 병렬 실행이 중단됩니다. 또한 1 대 1이있는 경우 mscorlib의 모든 네임 스페이스에 대해 50 개의 dll이 필요하거나 네임 스페이스에 대한 아이디어를 삭제해야합니다.
Conrad Frix

추가적인 수준의 간접 지향? 흠 .... dmst.aueb.gr/dds/pubs/inbook/beautiful_code/html/Spi07g.html
user541686

@gilles 질문을 편집하고 개선해 주셔서 감사합니다!
dharmatech

일부 요점은 Visual Studio에 고유하며 언어와 비교하는 것은 상당히 공정하지 않습니다 ( 예 : 프로젝트의 DLL 참조). 전체 .NET 환경에 대한 더 나은 비교는 Java + Eclipse입니다.
로스 패터슨

답변:


22

프레임 워크 디자인 가이드 라인 섹션 3.3 의 다음 주석 어셈블리 및 DLL 이름은 네임 스페이스와 어셈블리가 분리 된 이유에 대한 통찰력을 제공합니다.

BRAD ABRAMS CLR 설계 초기에 플랫폼 (네임 스페이스)의 개발자 관점과 플랫폼 (어셈블리)의 패키징 및 배포 관점을 분리하기로 결정했습니다. 이러한 분리를 통해 자체 기준에 따라 각각을 독립적으로 최적화 할 수 있습니다. 예를 들어, 기능적으로 관련된 유형 (예 : System.IO의 모든 I / O 항목)을 그룹화하기 위해 네임 스페이스를 자유롭게 고려할 수 있지만 어셈블리는 성능 (로드 시간), 배포, 서비스 또는 버전 관리 이유에 따라 고려할 수 있습니다. .


지금까지 가장 권위있는 소스 인 것 같습니다. 콘래드 감사합니다!
dharmatech

저주받은 정답을 얻기 위해 +1. 그러나 C #이 <X>를 수행하는 모든 " 질문은 다음과 같이 " Java does <X> 의 렌즈를 통해 볼 필요가 있습니다 . ... "는 C #이 태양과 Windows의 Java에 대한 Microsoft의 다른 의제.
로스 패터슨

6

유연성을 추가하고 필요할 때 라이브러리 (질문에서 모듈이라고 부르는 것)를로드 할 수 있습니다.

하나의 네임 스페이스, 여러 라이브러리 :

장점 중 하나는 라이브러리 하나를 다른 라이브러리로 쉽게 바꿀 수 있다는 것입니다. 데이터베이스와 관련된 모든 SQL 쿼리 및 기타 항목을 포함 하는 namespace MyCompany.MyApplication.DAL및 library 가 있다고 가정 해 봅시다 DAL.MicrosoftSQL.dll. 애플리케이션이 Oracle과 호환 DAL.Oracle.dll되도록하려면 동일한 네임 스페이스를 유지하면서 추가 하면됩니다. 이제부터는 Microsoft SQL Server와의 호환성이 필요한 고객을위한 하나의 라이브러리와 Oracle을 사용하는 고객을위한 다른 라이브러리와 함께 애플리케이션을 제공 할 수 있습니다.

이 수준에서 네임 스페이스를 변경하면 코드가 중복되거나 using각 데이터베이스의 소스 코드 내에서 모든 코드를 이동하고 변경해야 합니다.

하나의 라이브러리, 여러 네임 스페이스 :

하나의 라이브러리에 여러 네임 스페이스를 갖는 것도 가독성 측면에서 유리합니다. 클래스에서 네임 스페이스 중 하나만 사용하는 경우 파일 맨 위에이 네임 스페이스 만 추가합니다.

  • 큰 라이브러리의 모든 네임 스페이스를 갖는 것은 소스 코드를 읽는 사람과 작가 자신에게 다소 혼란 스럽습니다 .Intellisense는 주어진 맥락에서 제안 할 것이 너무 많습니다.

  • 더 작은 라이브러리를 사용하면 파일 당 하나의 라이브러리가 성능에 영향을 미칩니다. 각 라이브러리는 필요할 때 메모리에로드되고 응용 프로그램을 실행할 때 가상 컴퓨터에서 처리해야합니다. 로드 할 파일 수가 적 으면 성능이 약간 향상됩니다.


두 번째 경우에는 주어진 어셈블리가 많은 하위 폴더와 파일을 쉽게 가질 수 있기 때문에 파일 이름이 네임 스페이스와 분리 될 필요는 없습니다 (이러한 분리를 통해 분리가 훨씬 쉬워 짐). 또한 여러 어셈블리를 동일한 DLL에 포함시킬 수도 있습니다 (예 : ILMerge 사용 ). Java는이 접근법을 취합니다.
Brian

2

"네임 스페이스"와 "모듈"의 용어를 오버로드하기로 선택한 것 같습니다. 그들이 당신의 정의에 맞지 않을 때 "간접적 인"것으로 보는 것은 놀라운 일이 아닙니다.

C #을 포함하여 네임 스페이스를 지원하는 대부분의 언어에서 네임 스페이스는 모듈이 아닙니다. 네임 스페이스는 이름을 지정하는 방법입니다. 모듈은 동작 범위를 지정하는 방법입니다.

일반적으로 .Net 런타임은 모듈에 대한 개념을 지원하지만 (암시 적으로 사용하는 것과 약간 다른 정의를 가짐) 거의 사용되지 않습니다. 나는 다른 언어로 작성된 모듈에서 단일 DLL을 작성할 수 있도록 SharpDevelop로 빌드 된 프로젝트에서만 사용되는 것을 보았습니다. 대신 동적으로 연결된 라이브러리를 사용하여 라이브러리를 빌드합니다.

C #에서 네임 스페이스는 모두 같은 바이너리에있는 한 "간접 레이어"없이 확인됩니다. 필요한 간접 지시는 많은 생각을 할 필요가없는 컴파일러와 링커의 책임입니다. 여러 종속성이있는 프로젝트 빌드를 시작하면 외부 라이브러리를 참조하십시오. 프로젝트가 외부 라이브러리 (DLL)를 참조하면 컴파일러가이를 찾습니다.

Scheme에서 외부 라이브러리를로드 해야하는 경우 (#%require (lib "mylib.ss"))먼저 외우는 것처럼 먼저 외부 기능 인터페이스를 사용하거나 외부 함수 인터페이스를 사용해야합니다. 외부 바이너리를 사용하는 경우 외부 바이너리를 해결하는 작업량이 동일합니다. 대부분 라이브러리를 많이 사용했을 가능성이 높습니다.이를 기반으로하는 스키마 기반 심이 있지만 타사 라이브러리와 자체 통합을 작성해야하는 경우에는 "로드하기 위해 몇 가지 작업을 수행해야합니다" " 도서관.

Ruby에서 모듈, 네임 스페이스 및 파일 이름은 실제로 생각보다 훨씬 덜 연결되어 있습니다. LOAD_PATH는 일을 조금 복잡하게 만들고 모듈 선언은 어디에서나 가능합니다. C의 써드 파티 라이브러리는 여전히 (작은) 주름을 추가한다는 점을 제외하고는 아마도 Scheme에서 생각하는 방식으로 파이썬이 더 가까이 다가 가고 있습니다.

또한 Ruby, Python 및 Lisp와 같은 동적 유형 언어에는 일반적으로 정적 유형 언어와 "계약"에 대한 접근 방식이 없습니다. 동적으로 유형이 지정된 언어에서는 일반적으로 코드가 특정 메소드에 응답하는 일종의 "신사 동의"만 설정하고 클래스가 동일한 언어를 사용하는 것으로 보이는 경우 모두 좋습니다. 정적 형식 언어에는 컴파일 타임에 이러한 규칙을 적용하기위한 추가 메커니즘이 있습니다. C #에서 이러한 계약을 사용하면 이러한 인터페이스에 대한 최소한의 유용한 준수 보장을 제공 할 수 있습니다. 따라서 동일한 계약에 대해 컴파일하기 때문에 플러그인과 대체를 어느 정도의 공통성을 보장 할 수 있습니다. Ruby 또는 Scheme에서는 런타임시 작동하는 테스트를 작성하여 이러한 계약을 확인합니다.

메소드 호출에는 이중 디스패치가 필요하지 않으므로 이러한 컴파일 시간 보장으로 측정 가능한 성능 이점이 있습니다. Lisp, Ruby, JavaScript 또는 다른 곳에서 이러한 이점을 얻으려면 이제 특수 VM에서 적시에 정적으로 정적 컴파일 클래스를 작성하는 약간의 이국적인 메커니즘이 필요합니다.

C # 생태계가 여전히 상대적으로 미성숙 한 지원을하는 것 중 하나는 이진 종속성 관리입니다. Java는 몇 년 동안 Maven을 사용하여 모든 필수 종속성을 확인하는 반면 C #에는 여전히 전략적으로 파일을 적절한 장소에 미리 배치하는 상당히 원시적 인 MAKE와 유사한 접근 방식이 있습니다.


1
종속성 관리와 관련하여 NuGet을 살펴볼 수 있습니다 . 여기의 좋은 기사 필 Haack에서 그것에 대해이
콘래드 Frix

내가 사용한 R6RS Scheme 구현에서 (예 : Ikarus, Chez 및 Ypsilon) 종속성은 라이브러리 가져 오기를 기반으로 자동으로 처리됩니다. 종속성을 찾고 필요한 경우 나중에 가져 오기 위해 컴파일하고 캐시합니다.
dharmatech

Nuget에 대해 잘 알고 있으므로 "상대적으로 미숙"하다는 의견
JasonTrue
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.