Управляемые типы (C++/CLI)

Visual C++ позволяет получить доступ к функциям .NET через управляемые типы, которые обеспечивают поддержку функций среды CLR и подвергаются преимуществам и ограничениям среды выполнения.

Управляемые типы и основная функция

При написании приложения с помощью /clrаргументы main() функции не могут быть управляемым типом.

Пример правильной подписи:

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

платформа .NET Framework эквиваленты собственных типов C++

В следующей таблице показаны ключевое слово для встроенных типов Visual C++, которые являются псевдонимами предопределенных типов в пространстве имен Системы.

Тип Visual C++ Тип .NET Framework
void System.Void
bool System.Boolean
signed char System.SByte
unsigned char System.Byte
wchar_t System.Char
short и signed short System.Int16
unsigned short System.UInt16
int, signed int, long и signed long System.Int32
unsigned int и unsigned long System.UInt32
__int64 и signed __int64 System.Int64
unsigned __int64 System.UInt64
float System.Single
double и long double System.Double

Дополнительные сведения о параметре компилятора по умолчанию или см. в разделе /J (Тип по умолчанию signed charcharunsigned).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 S в nested_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. Он должен успешно компилироваться. Затем уменьшите доступность вызываемого метода. Перекомпиляция changeaccess.cpp с параметром /DCHANGE_ACCESSкомпилятора. Он делает access_me метод protected, а не publicтаким образом, чтобы его нельзя было вызывать извне Test или его производных. Без повторной компиляции referencing.exeповторно запустите приложение. Возникает.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;
}

См. также

Программирование .NET с помощью C++/CLI (Visual C++)
Взаимодействие с другими языками .NET (C++/CLI)
Управляемые типы (C++/CLI)
#using Директива