Typy zarządzane (C++/CLI)

Program Visual C++ umożliwia dostęp do funkcji platformy .NET za pośrednictwem typów zarządzanych, które zapewniają obsługę funkcji środowiska uruchomieniowego języka wspólnego i podlegają zaletom i ograniczeniom środowiska uruchomieniowego.

Typy zarządzane i główna funkcja

Podczas pisania aplikacji przy użyciu metody /clrargumenty main() funkcji nie mogą być typu zarządzanego.

Przykładem prawidłowego podpisu jest:

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

Odpowiedniki programu .NET Framework dla typów natywnych języka C++

W poniższej tabeli przedstawiono słowa kluczowe dla wbudowanych typów języka Visual C++, które są aliasami wstępnie zdefiniowanych typów w przestrzeni nazw System .

Typ visual C++ Typ programu .NET Framework
void System.Void
bool System.Boolean
signed char System.SByte
unsigned char System.Byte
wchar_t System.Char
short i signed short System.Int16
unsigned short System.UInt16
int, signed int, longi signed long System.Int32
unsigned int i unsigned long System.UInt32
__int64 i signed __int64 System.Int64
unsigned __int64 System.UInt64
float System.Single
double i long double System.Double

Aby uzyskać więcej informacji na temat opcji kompilatora domyślnej wartości signed char lub unsigned char, zobacz /J (Typ domyślny char to unsigned).

Problemy z wersją typów wartości zagnieżdżonych w typach natywnych

Rozważ użycie składnika zestawu podpisanego (silnej nazwy) używanego do kompilowania zestawu klienta. Składnik zawiera typ wartości używany w kliencie jako typ elementu członkowskiego natywnej unii, klasy lub tablicy. Jeśli przyszła wersja składnika zmieni rozmiar lub układ typu wartości, klient musi zostać ponownie skompilowany.

Utwórz plik klucza za pomocą pliku sn.exe (sn -k mykey.snk).

Przykład

Poniższy przykład jest składnikiem.

// 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);
   }
};

Ten przykład jest klientem:

// 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();
}

W przykładzie są generowane następujące dane wyjściowe:

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

Komentarze

Jeśli jednak dodasz do elementu innego elementu członkowskiego struct S (na przykład double d;) i ponownie skompilujesz składnik bez konieczności ponownego kompilowania klienta, wynik jest nieobsługiwanym wyjątkiem (typu System.IO.FileLoadException).nested_value_types.cpp

Jak przetestować równość

W poniższym przykładzie test równości używający rozszerzeń zarządzanych dla języka C++ jest oparty na tym, co odnoszą się do dojść.

Przykład

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

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

Il dla tego programu pokazuje, że wartość zwracana jest implementowana przy użyciu wywołania metody op_Equality.

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

Jak zdiagnozować i rozwiązać problemy ze zgodnością zestawu

Gdy wersja zestawu, do których odwołuje się w czasie kompilacji, nie jest zgodna z wersją zestawu, do których odwołuje się środowisko uruchomieniowe, mogą wystąpić różne problemy.

Po skompilowaniu zestawu inne zestawy mogą być przywołyne ze składnią #using . Podczas kompilacji te zestawy są dostępne przez kompilator. Informacje z tych zestawów służą do podejmowania decyzji dotyczących optymalizacji.

Jeśli jednak zestaw, do którego odwołuje się odwołanie, zostanie zmieniony i ponownie skompilowany, ponownie skompiluj zestaw odwołujące się, który jest od niego zależny. W przeciwnym razie zestawy mogą stać się niezgodne. Decyzje dotyczące optymalizacji, które były prawidłowe na początku, mogą nie być poprawne dla nowej wersji zestawu. Z powodu tych niezgodności mogą wystąpić różne błędy środowiska uruchomieniowego. W takich przypadkach nie ma określonego wyjątku. Sposób zgłaszania błędu w czasie wykonywania zależy od charakteru zmiany kodu, która spowodowała problem.

Te błędy nie powinny być problemem w końcowym kodzie produkcyjnym, o ile cała aplikacja zostanie ponownie skompilowana dla wydanej wersji produktu. Zestawy wydane publicznie powinny być oznaczone oficjalnym numerem wersji, co zapewni uniknięcie tych problemów. Aby uzyskać więcej informacji, zobacz Przechowywanie wersji zestawu.

Aby zdiagnozować i naprawić błąd niezgodności

W kodzie, który odwołuje się do innego zestawu, mogą wystąpić wyjątki środowiska uruchomieniowego lub inne warunki błędu. Jeśli nie możesz zidentyfikować innej przyczyny, problem może być nieaktualnym zestawem.

  1. Najpierw izoluj i odtwórz wyjątek lub inny warunek błędu. Problem, który występuje z powodu nieaktualnego wyjątku, powinien być powtarzalny.

  2. Sprawdź znacznik czasu wszystkich zestawów, do których odwołuje się aplikacja.

  3. Jeśli znaczniki czasu wszystkich zestawów, do których odwołuje się odwołanie, są późniejsze niż sygnatura czasowa ostatniej kompilacji aplikacji, aplikacja jest nieaktualna. Jeśli jest nieaktualna, ponownie skompiluj aplikację przy użyciu najnowszych zestawów i w razie potrzeby zmodyfikuj kod.

  4. Uruchom ponownie aplikację, wykonaj kroki, które odtwórz problem, i sprawdź, czy wyjątek nie występuje.

Przykład

Poniższy program ilustruje problem: najpierw zmniejsza dostępność metody, a następnie próbuje uzyskać dostęp do tej metody w innym zestawie bez ponownej kompilacji. Najpierw skompiluj changeaccess.cpp . Jest to zestaw, do którego się odwołujesz, który zmieni się. Następnie skompiluj plik referencing.cpp. Powinna zostać pomyślnie skompilowana. Następnie zmniejsz dostępność wywoływanej metody. Skompiluj changeaccess.cpp ponownie za pomocą opcji /DCHANGE_ACCESSkompilatora . Sprawia, że access_me metoda protected, a publicnie , więc nie może być wywoływana z zewnątrz Test ani jej pochodnych. Bez ponownego komplikowania referencing.exeuruchom ponownie aplikację. Następuje MethodAccessException wystąpienie.

// 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;
  }

};

Oto źródło zestawu odwołującego się do:

// 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;
}

Zobacz też

Programowanie .NET za pomocą języka C++/CLI (Visual C++)
Współdziałanie z innymi językami platformy .NET (C++/CLI)
Typy zarządzane (C++/CLI)
#using Dyrektywy