Управляемые типы (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

Дополнительные сведения о параметре компилятора по умолчанию или signed charunsigned charсм. в разделе /J (тип по умолчанию charunsigned).

Проблемы версий, связанные с типами значений, вложенными в собственные типы

Рассмотрим подписанный компонент сборки (строгое имя), используемый для сборки клиентской сборки. Компонент содержит тип значения, который используется в клиенте в качестве типа для члена собственного объединения, класса или массива. Если будущая версия компонента изменяет размер или макет типа значения, клиент должен быть перекомпилирован.

Создайте файл ключа с 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 Директива