관리되는 형식(C++/CLI)

Visual C++를 사용하면 관리되는 형식을 통해 .NET 기능에 액세스할 수 있습니다. 이 기능은 공용 언어 런타임의 기능을 지원하며 런타임의 장점과 제한 사항이 적용됩니다.

관리되는 형식 및 기본 함수

애플리케이션을 사용하여 /clr작성할 때 함수의 인수는 main() 관리되는 형식일 수 없습니다.

적절한 서명의 예는 다음과 같습니다.

// managed_types_and_main.cpp
// compile with: /clr
int main(int, char*[], char*[]) {}

C++ 네이티브 형식에 해당하는 .NET Framework

다음 표에서는 시스템 네임스페이스에서 미리 정의된 형식의 별칭인 기본 제공 Visual C++ 형식에 대한 키워드(keyword) 보여 줍니다.

Visual C++ 형식 .NET Framework 형식
void System.Void
bool System.Boolean
signed char System.SByte
unsigned char System.Byte
wchar_t System.Char
shortsigned short System.Int16
unsigned short System.UInt16
int, signed int, longsigned long System.Int32
unsigned intunsigned long System.UInt32
__int64signed __int64 System.Int64
unsigned __int64 System.UInt64
float System.Single
doublelong double System.Double

컴파일러 옵션의 기본값 또는 기본값 signed char 에 대한 자세한 내용은 (기본 char 형식은 unsigned)을 참조 /J 하세요.unsigned char

네이티브 형식에 중첩된 값 형식에 대한 버전 문제

클라이언트 어셈블리를 빌드하는 데 사용되는 서명된(강력한 이름) 어셈블리 구성 요소를 고려합니다. 구성 요소에는 네이티브 공용 구조체, 클래스 또는 배열의 멤버에 대한 형식으로 클라이언트에서 사용되는 값 형식이 포함됩니다. 이후 버전의 구성 요소가 값 형식의 크기 또는 레이아웃을 변경하는 경우 클라이언트를 다시 컴파일해야 합니다.

sn.exe(sn -k mykey.snk)를 사용하여 키 파일을 만듭니다.

예시

다음 샘플은 구성 요소입니다.

// nested_value_types.cpp
// compile with: /clr /LD
using namespace System::Reflection;
[assembly:AssemblyVersion("1.0.0.*"),
assembly:AssemblyKeyFile("mykey.snk")];

public value struct S {
   int i;
   void Test() {
      System::Console::WriteLine("S.i = {0}", i);
   }
};

이 샘플은 클라이언트입니다.

// nested_value_types_2.cpp
// compile with: /clr
#using <nested_value_types.dll>

struct S2 {
   S MyS1, MyS2;
};

int main() {
   S2 MyS2a, MyS2b;
   MyS2a.MyS1.i = 5;
   MyS2a.MyS2.i = 6;
   MyS2b.MyS1.i = 10;
   MyS2b.MyS2.i = 11;

   MyS2a.MyS1.Test();
   MyS2a.MyS2.Test();
   MyS2b.MyS1.Test();
   MyS2b.MyS2.Test();
}

이 예에서는 다음과 같은 출력을 생성합니다.

S.i = 5
S.i = 6
S.i = 10
S.i = 11

설명

그러나 다른 멤버를 struct Snested_value_types.cpp 에 추가하고(예: double d;) 클라이언트를 다시 컴파일하지 않고 구성 요소를 다시 컴파일하는 경우 결과는 처리되지 않은 예외(형식 System.IO.FileLoadException)입니다.

같음을 테스트하는 방법

다음 샘플에서는 C++용 관리되는 확장을 사용하는 같음 테스트는 핸들이 참조하는 내용을 기반으로 합니다.

예시

// mcppv2_equality_test.cpp
// compile with: /clr /LD
using namespace System;

bool Test1() {
   String ^ str1 = "test";
   String ^ str2 = "test";
   return (str1 == str2);
}

이 프로그램의 IL은 반환 값이 호출 op_Equality을 사용하여 구현됨을 보여줍니다.

IL_0012:  call       bool [mscorlib]System.String::op_Equality(string, string)

어셈블리 호환성 문제를 진단하고 해결하는 방법

컴파일 시간에 참조되는 어셈블리 버전이 런타임에 참조되는 어셈블리 버전과 일치하지 않으면 다양한 문제가 발생할 수 있습니다.

어셈블리가 컴파일되면 다른 어셈블리를 구문으로 #using 참조할 수 있습니다. 컴파일하는 동안 이러한 어셈블리는 컴파일러에서 액세스합니다. 이러한 어셈블리의 정보는 최적화 결정을 내리는 데 사용됩니다.

그러나 참조된 어셈블리가 변경되고 다시 컴파일되는 경우 해당 어셈블리에 종속된 참조 어셈블리도 다시 컴파일합니다. 그렇지 않으면 어셈블리가 호환되지 않을 수 있습니다. 처음에 유효한 최적화 결정은 새 어셈블리 버전에 대해 올바르지 않을 수 있습니다. 이러한 비호환성으로 인해 다양한 런타임 오류가 발생할 수 있습니다. 이러한 경우에 생성되는 특정 예외는 없습니다. 런타임에 오류가 보고되는 방식은 문제를 일으킨 코드 변경의 특성에 따라 달라집니다.

릴리스된 버전의 제품에 대해 전체 애플리케이션을 다시 빌드하는 한 최종 프로덕션 코드에서 이러한 오류는 문제가 되지 않습니다. 공용으로 릴리스되는 어셈블리는 공식 버전 번호로 표시되어야 하므로 이러한 문제를 방지할 수 있습니다. 자세한 내용은 어셈블리 버전 관리를 참조하세요.

비호환성 오류를 진단하고 해결하려면

다른 어셈블리를 참조하는 코드에서 런타임 예외 또는 기타 오류 조건이 발생할 수 있습니다. 다른 원인을 식별할 수 없는 경우 문제가 오래된 어셈블리일 수 있습니다.

  1. 먼저 예외 또는 기타 오류 조건을 격리하고 재현합니다. 오래된 예외로 인해 발생하는 문제를 재현할 수 있어야 합니다.

  2. 애플리케이션에서 참조되는 어셈블리의 타임스탬프를 확인합니다.

  3. 참조된 어셈블리의 타임스탬프가 애플리케이션의 마지막 컴파일 타임스탬프보다 늦으면 애플리케이션이 만료됩니다. 최신이 아닌 경우 애플리케이션을 최신 어셈블리와 다시 컴파일하고 필요한 경우 코드를 편집합니다.

  4. 애플리케이션을 다시 실행하고, 문제를 재현하는 단계를 수행하고, 예외가 발생하지 않는지 확인합니다.

예시

다음 프로그램은 문제를 보여 줍니다. 먼저 메서드의 접근성을 줄인 다음 다시 컴파일하지 않고 다른 어셈블리에서 해당 메서드에 액세스하려고 시도합니다. 먼저 컴파일합니다 changeaccess.cpp . 변경될 참조된 어셈블리입니다. 그런 다음, .를 컴파일합니다 referencing.cpp. 성공적으로 컴파일되어야 합니다. 다음으로, 호출된 메서드의 접근성을 줄입니다. 컴파일러 옵션을 /DCHANGE_ACCESS사용하여 다시 컴파일 changeaccess.cpp 합니다. 메서드가 access_me 아닌 public외부 protected또는 파생물에서 Test 호출할 수 없도록 합니다. 다시 컴파일하지 referencing.exe않고 애플리케이션을 다시 실행합니다. A MethodAccessException 가 발생합니다.

// changeaccess.cpp
// compile with: /clr:safe /LD
// After the initial compilation, add /DCHANGE_ACCESS and rerun
// referencing.exe to introduce an error at runtime. To correct
// the problem, recompile referencing.exe

public ref class Test {
#if defined(CHANGE_ACCESS)
protected:
#else
public:
#endif

  int access_me() {
    return 0;
  }

};

참조 어셈블리의 원본은 다음과 같습니다.

// referencing.cpp
// compile with: /clr:safe
#using <changeaccess.dll>

// Force the function to be inline, to override the compiler's own
// algorithm.
__forceinline
int CallMethod(Test^ t) {
  // The call is allowed only if access_me is declared public
  return t->access_me();
}

int main() {
  Test^ t = gcnew Test();
  try
  {
    CallMethod(t);
    System::Console::WriteLine("No exception.");
  }
  catch (System::Exception ^ e)
  {
    System::Console::WriteLine("Exception!");
  }
  return 0;
}

참고 항목

C++/CLI를 사용한 .NET 프로그래밍(Visual C++)
다른 .NET 언어와의 상호 운용성(C++/CLI)
관리되는 형식(C++/CLI)
#using 지시문