문제

누구나 할 수 있나요 설명하다 다음 행동은?

요약하자면, 여러 개를 생성하면 CLS 규격 Visual Studio 2008의 라이브러리가 공통 네임스페이스 루트를 공유하도록 하면 다른 라이브러리를 참조하는 라이브러리는 필요하다 해당 라이브러리의 참조를 사용하지 않더라도 참조에 대한 참조입니다.

한 문장으로 설명하기는 매우 어렵지만 동작을 재현하는 단계는 다음과 같습니다(네임스페이스에 세심한 주의를 기울이십시오).

LibraryA라는 라이브러리를 만들고 해당 라이브러리에 단일 클래스를 추가합니다.

namespace Ploeh
{
    public abstract class Class1InLibraryA
    {
    }
}

다음을 추가하여 라이브러리가 CLS 규격인지 확인하세요. [assembly: CLSCompliant(true)] AssemblyInfo.cs에.

LibraryB라는 다른 라이브러리를 만들고 LibraryA를 참조합니다.LibraryB에 다음 클래스를 추가합니다.

namespace Ploeh.Samples
{
    public class Class1InLibraryB : Class1InLibraryA
    {
    }
}

그리고

namespace Ploeh.Samples
{
    public abstract class Class2InLibraryB
    {
    }
}

LibraryB도 CLS 규격인지 확인하세요.

Class1InLibraryB는 LibraryA의 유형에서 파생되는 반면 Class2InLibraryB는 그렇지 않습니다.

이제 LibraryC라는 세 번째 라이브러리를 만들고 LibraryB(LibraryA는 아님)를 참조합니다.다음 클래스를 추가합니다.

namespace Ploeh.Samples.LibraryC
{
    public class Class1InLibraryC : Class2InLibraryB
    {
    }
}

여전히 컴파일되어야 합니다.Class1InLibraryC는 LibraryB의 클래스에서 파생됩니다. LibraryA의 어떤 유형도 사용하지 않습니다..

또한 Class1InLibraryC는 LibraryB에 정의된 네임스페이스 계층 구조의 일부인 네임스페이스에 정의되어 있습니다.

지금까지 LibraryC에는 LibraryA에 대한 참조가 없으며 LibraryA의 유형을 사용하지 않으므로 솔루션이 컴파일됩니다.

이제 LibraryC CLS도 준수하도록 만드세요.갑자기 솔루션이 더 이상 컴파일되지 않고 다음 오류 메시지가 표시됩니다.

'Ploeh.Class1InLibraryA' 유형이 참조되지 않은 어셈블리에 정의되어 있습니다.'Ploeh, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' 어셈블리에 대한 참조를 추가해야 합니다.

다음 방법 중 하나로 솔루션을 다시 컴파일할 수 있습니다.

  • LibraryC에서 CLS 규정 준수 제거
  • LibraryA에 대한 참조를 추가합니다(필요하지는 않지만).
  • LibraryB의 네임스페이스 계층 구조에 포함되지 않도록 LibraryC의 네임스페이스를 변경합니다(예:Fnaah.Samples.LibraryC)
  • Class1InLibraryB의 네임스페이스를 변경합니다(즉, ~ 아니다 LibracyC에서 사용됨)이 LibraryC의 네임스페이스 계층 구조(예:Ploeh.Samples.LibraryB로)

네임스페이스 계층 구조와 CLS 규정 준수 사이에는 이상한 상호 작용이 있는 것 같습니다.

이 문제는 위 목록의 옵션 중 하나를 선택하여 해결할 수 있지만 누구든지 설명할 수 있습니까? 이유 이 행동 뒤에?

도움이 되었습니까?

해결책

CLS의 공식 문서를 살펴봤습니다(http://msdn.microsoft.com/en-us/netframework/aa569283.aspx), 하지만 간단한 답을 찾기도 전에 머리가 터질 것 같았습니다.

그러나 내 생각에 컴파일러는 LibraryC의 CLS 준수 여부를 확인하기 위해 LibraryA와의 가능한 명명 충돌을 조사해야 한다는 것이 기본이라고 생각합니다.

컴파일러는 "정의 어셈블리 외부에서 액세스할 수 있거나 표시되는 형식의 부분"(CLS 규칙 1)을 모두 확인해야 합니다.

공용 클래스 Class1InLibraryC는 Class2InLibraryB를 상속하므로 LibraryA에 대한 CLS 준수도 확인해야 합니다. 특히 "Ploeh.*"가 이제 CLS 규칙 5 "CLS 준수 범위에 도입된 모든 이름은 고유하고 독립적이어야 합니다"의 "범위 내에" 있기 때문입니다. 일종의".

Class1InLibraryB 또는 Class1InLibraryC의 네임스페이스를 변경하여 고유하게 만드는 것은 컴파일러가 더 이상 이름 충돌 가능성이 없다고 확신하는 것 같습니다.

옵션 (2)를 선택하고 참조를 추가하고 컴파일하면 참조가 결과 어셈블리 메타데이터에 실제로 표시되지 않으므로 이는 컴파일/검증 시간 종속성일 뿐입니다.

다른 팁

CLS는 생성된 어셈블리에 적용되는 규칙 집합이며 언어 간 상호 운용성을 지원하도록 설계되었습니다.어떤 의미에서 이는 언어 및 플랫폼에 구애받지 않도록 유형이 따라야 하는 가장 작은 공통 규칙 하위 집합을 정의합니다.CLS 준수는 정의 어셈블리 외부에 표시되는 항목에만 적용됩니다.

CLS 규격 코드가 따라야 하는 몇 가지 지침을 살펴보면 다음과 같습니다.

  • 프로그래밍 언어에서 일반적으로 키워드로 사용되는 이름을 사용하지 마십시오.
  • 프레임워크 사용자가 중첩 유형을 작성할 수 있을 것이라고 기대하지 마십시오.
  • 서로 다른 인터페이스에서 동일한 이름과 서명을 가진 메서드 구현이 독립적이라고 가정합니다.

CLS 준수를 결정하는 규칙은 다음과 같습니다.

  • 어셈블리가 명시적 System.CLSCompliantAttribute를 전달하지 않는 경우 System.CLSCompliantAttribute(false)를 전달하는 것으로 가정합니다.
  • 기본적으로 형식은 바깥쪽 형식(중첩 형식의 경우)의 CLS 준수 특성을 상속하거나 해당 어셈블리에 연결된 준수 수준(최상위 형식의 경우)을 획득합니다.
  • 기본적으로 다른 멤버(메서드, 필드, 속성 및 이벤트)는 해당 형식의 CLS 규격을 상속합니다.

이제 컴파일러에 관한 한(CLS 규칙 1) 어셈블리 외부로 내보낼 모든 정보에 CLS 준수 규칙을 적용할 수 있어야 하며 모든 정보가 공개된 경우 해당 형식을 CLS 준수로 간주해야 합니다. 액세스 가능한 부분(다른 어셈블리에서 실행되는 코드에 사용할 수 있는 클래스, 인터페이스, 메서드, 필드, 속성 및 이벤트)

  • CLS 규격 형식으로만 구성된 서명이 있거나
  • CLS 규격이 아닌 것으로 구체적으로 표시되어 있습니다.

CTS 규칙에 따르면 범위는 단순히 이름의 그룹/컬렉션이며, 범위 내에서 이름은 종류(메서드, 필드, 중첩 유형, 속성, 이벤트)가 다르거나 서명이 다른 여러 엔터티를 참조할 수 있습니다.명명된 엔터티는 정확히 하나의 범위에 이름을 가지므로 해당 항목을 식별하려면 범위와 이름을 모두 적용해야 합니다.범위는 이름을 한정합니다.

유형에 이름이 지정되므로 유형 이름도 범위로 그룹화됩니다.유형을 완전히 식별하려면 유형 이름이 범위에 따라 정규화되어야 합니다.유형 이름은 해당 유형의 구현을 포함하는 어셈블리에 의해 범위가 지정됩니다.

CLS 규격 범위의 경우 이름이 동일하고 오버로드를 통해 확인되는 경우를 제외하고 모든 이름은 종류에 관계없이 고유해야 합니다.즉, CTS에서는 단일 형식이 필드와 메서드에 동일한 이름을 사용할 수 있도록 허용하지만 CLS에서는 그렇지 않습니다(CLS 규칙 5).

한 단계 더 나아가 CLS 규격 형식은 CLS 규격이 아닌 형식(CLS 규칙 20)의 구현을 요구하지 않아야 하며 다른 CLS 규격 형식(CLS 규칙 23)에서도 상속해야 합니다.

한 어셈블리 참조 리소스 범위의 구현이 다른 어셈블리에 속하거나 소유된 경우 어셈블리는 다른 어셈블리에 종속될 수 있습니다.

  • 다른 어셈블리에 대한 모든 참조는 현재 어셈블리 범위의 제어에 따라 확인됩니다.
  • 특정 구현이 실행되는 어셈블리 범위를 확인하는 것은 항상 가능합니다.해당 어셈블리 범위에서 발생하는 모든 요청은 해당 범위를 기준으로 해결됩니다.

이 모든 것이 궁극적으로 의미하는 바는 형식의 CLS 준수를 확인하려면 컴파일러가 다음을 확인할 수 있어야 한다는 것입니다. 모두 해당 유형의 공용 부분도 CLS 규격입니다.이는 이름이 범위 내에서 고유하고, 자체 구현의 일부에 대해 CLS 규격이 아닌 형식에 의존하지 않고, CLS 규격인 다른 형식에서 상속되는지 확인해야 함을 의미합니다.이를 수행하는 유일한 방법은 해당 형식이 참조하는 모든 어셈블리를 검사하는 것입니다.

Visual Studio의 빌드 단계는 본질적으로 MSBuild 실행을 위한 GUI 래퍼이며, 이는 궁극적으로 C# 명령줄 컴파일러를 호출하는 스크립트 방식에 지나지 않습니다.컴파일러가 형식의 CLS 규격을 확인하려면 형식이 참조하는 모든 어셈블리(프로젝트 아님)를 알고 찾을 수 있어야 합니다.이는 MSBuild 및 궁극적으로 Visual Studio를 통해 호출되므로 Visual Studio(MSBuild)가 해당 어셈블리에 대해 알리는 유일한 방법은 해당 어셈블리를 참조로 포함하는 것입니다.

분명히, 컴파일러는 CLS 규격을 확인하고 성공적으로 컴파일하기 위해 "누락된" 참조가 있다는 것을 알아낼 수 있으므로, 우리를 대신하여 해당 참조를 자동으로 포함할 수만 있었다면 좋았을 것입니다.여기서 문제는 결정하는 것입니다. 어느 포함할 어셈블리 버전 어디 해당 어셈블리는 파일 시스템에 있습니다.개발자에게 해당 정보를 제공하도록 강요함으로써 컴파일러는 올바른 정보가 제공되도록 보장합니다.이는 또한 모든 종속 어셈블리가 Debug/bin 또는 Release/bin 폴더를 빌드하는 동안 애플리케이션이 컴파일된 후 실행될 때 올바른 디렉터리에 있도록 합니다.

이 문제는 Visual Studio 14에서 사용할 수 있는 Roslyn에서 해결되었습니다.
2014년 7월 현재의 CTP를 이용할 수 있습니다. 여기.
보다 이 버그 보고서 자세한 내용은.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top