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

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

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

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

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

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

Эквиваленты собственным типам C++ в .NET Framework

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

Тип 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

Дополнительные сведения о параметре компилятора по умолчанию или unsigned charсм. в разделе /J (Тип по умолчанию charunsigned)signed 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 Директива