[.net] Microsoft는 순환 참조가있는 어셈블리를 어떻게 만들었습니까?

.NET BCL에는 다음 사이에 순환 참조가 있습니다.

  • System.dllSystem.Xml.dll
  • System.dllSystem.Configuration.dll
  • System.Xml.dllSystem.Configuration.dll

다음은 내가 의미하는 바를 보여주는 .NET Reflector의 스크린 샷입니다.

여기에 이미지 설명 입력

Microsoft가 이러한 어셈블리를 만든 방법은 나에게 미스터리입니다. 이를 허용하려면 특별한 컴파일 프로세스가 필요합니까? 여기서 흥미로운 일이 벌어지고 있다고 생각합니다.



답변

Mono Project가 어떻게이 작업을 수행하는지 알 수 있습니다. 정리는 매우 간단하지만 코드가 엉망입니다.

먼저 System.Xml.dll에 대한 참조가 필요한 부분없이 System.Configuration.dll을 컴파일합니다. 그런 다음 일반적인 방식으로 System.Xml.dll을 컴파일합니다. 이제 마법이 온다. System.Xml.dll에 대한 참조가 필요한 부분으로 System.configuration.dll을 다시 컴파일합니다. 이제 순환 참조를 사용한 성공적인 컴파일이 있습니다.

요컨대 :

  • A는 B가 필요한 코드와 B에 대한 참조없이 컴파일됩니다.
  • B가 컴파일됩니다.
  • A가 다시 컴파일됩니다.

답변

RBarryYoung과 Dykam이 뭔가에 있습니다. Microsoft는 ILDASM을 사용하여 어셈블리를 분해하고 모든 내부 / 개인 항목 및 메서드 본문을 제거하고 IL을 다시 컴파일 (ILSM 사용)하여 ‘탈수 어셈블리’또는 메타 데이터 어셈블리로 다시 컴파일하는 내부 도구를 사용합니다. 이것은 어셈블리의 공용 인터페이스가 변경 될 때마다 수행됩니다.

빌드하는 동안 실제 어셈블리 대신 메타 데이터 어셈블리가 사용됩니다. 그렇게하면 사이클이 깨집니다.


답변

Dykam이 설명하는 방식으로 수행 할 수 있지만 Visual Studio는이를 수행하지 못하도록 차단합니다.

명령 줄 컴파일러 csc.exe를 직접 사용해야합니다.

  1. csc / target : library ClassA.cs

  2. csc / target : library ClassB.cs /reference:ClassA.dll

  3. csc / target : library ClassA.cs ClassC.cs /reference:ClassB.dll


//ClassA.cs
namespace CircularA {
    public class ClassA {
    }
}


//ClassB.cs
using CircularA;
namespace CircularB {
    public class ClassB : ClassA  {
    }
}


//ClassC.cs
namespace CircularA {
    class ClassC : ClassB {
    }
}


답변

프로젝트 참조를 사용하지 않는 한 Visual Studio에서 매우 쉽게 수행 할 수 있습니다. 다음을 시도해보십시오.

  1. Visual Studio 열기
  2. 2 개의 클래스 라이브러리 프로젝트 “ClassLibrary1″및 “ClassLibrary2″를 만듭니다.
  3. 짓다
  4. ClassLibrary1에서 3 단계에서 만든 dll을 찾아 ClassLibrary2에 대한 참조를 추가합니다.
  5. ClassLibrary2에서 3 단계에서 만든 dll을 찾아 ClassLibrary1에 대한 참조를 추가합니다.
  6. 다시 빌드 (참고 : 두 프로젝트 모두에서 변경 한 경우 두 참조를 “새로”만들기 위해 두 번 빌드해야 함)

그래서 이것이 당신이하는 방법입니다. 하지만 진지하게 … 실제 프로젝트에서 절대하지 마세요! 그렇게한다면, 산타는 올해 어떤 선물도주지 않을 것입니다.


답변

비순환 어셈블리 집합으로 시작하고 ILMerge를 사용하여 더 작은 어셈블리를 논리적으로 관련된 그룹으로 통합하여 수행 할 수 있다고 생각합니다.


답변

글쎄, 나는 그것을 Windows에서 한 적이 없지만 실용적인 조상 역할을 한 많은 compile-link-rtl 환경에서 해왔습니다. 먼저 상호 참조없이 스텁 “대상”을 만든 다음 연결 한 다음 순환 참조를 추가 한 다음 다시 연결합니다. 링커는 일반적으로 순환 참조 또는 후속 참조 체인에 대해 신경 쓰지 않고 각 참조를 자체적으로 해결할 수 있는지에 만 관심이 있습니다.

따라서 서로를 참조해야하는 두 개의 라이브러리 A와 B가있는 경우 다음과 같이 시도하십시오.

  1. B에 대한 참조없이 A를 연결합니다.
  2. B 를 A에 대한 참조 연결 합니다.
  3. 링크 A, 참조를 B에 추가합니다.

Dykam은 좋은 지적을합니다. .Net에서 링크가 아닌 컴파일이지만 원칙은 동일합니다. 내 보낸 진입 점을 사용하여 상호 참조 된 소스를 만듭니다. 밖. 그렇게 만드십시오. 그런 다음 외부 참조의 스텁을 풀고 다시 빌드하십시오. 이것은 특별한 도구 없이도 작동 할 것입니다. 사실이 접근 방식은 제가 사용해 본 모든 운영 체제에서 작동했습니다 (그 중 약 6 개). 분명히 자동화하는 것이 큰 도움이 될 것입니다.


답변

한 가지 가능한 접근 방식은 조건부 컴파일 (#if)을 사용하여 다른 어셈블리에 종속되지 않는 System.dll을 먼저 컴파일 한 다음 다른 어셈블리를 컴파일 한 다음 마지막으로 System.dll을 다시 컴파일하여 Xml 및 구성.