Управляемые типы (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 char
unsigned char
см. в разделе /J
(тип по умолчанию char
— unsigned
).
Проблемы версий, связанные с типами значений, вложенными в собственные типы
Рассмотрим подписанный компонент сборки (строгое имя), используемый для сборки клиентской сборки. Компонент содержит тип значения, который используется в клиенте в качестве типа для члена собственного объединения, класса или массива. Если будущая версия компонента изменяет размер или макет типа значения, клиент должен быть перекомпилирован.
Создайте файл ключа с 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
. Во время компиляции компилятор обращается к этим сборкам. Сведения из этих сборок используются для принятия решений по оптимизации.
Однако если сборка, на которую указывает ссылка, изменяется и перекомпилируется, также перекомпилируется зависимую от нее сборку. В противном случае сборки могут стать несовместимыми. Решения по оптимизации, которые были действительными на первый взгляд, могут быть неправильными для новой версии сборки. Из-за этих несовместимости могут возникать различные ошибки среды выполнения. В таких случаях не возникает никаких конкретных исключений. Способ сообщения о сбое во время выполнения зависит от характера изменения кода, вызвавшего проблему.
Эти ошибки не должны быть проблемой в окончательном рабочем коде, если все приложение перестроено для выпущенной версии продукта. Сборки, выпущенные для общественности, должны быть помечены официальным номером версии, что позволит избежать этих проблем. Дополнительные сведения см. в разделе Версии сборок.
Диагностика и устранение ошибки несовместимости
В коде, который ссылается на другую сборку, могут возникнуть исключения среды выполнения или другие ошибки. Если вы не можете определить другую причину, проблема может быть устаревшей сборки.
Сначала изолируйте и воспроизведите исключение или другое условие ошибки. Проблема, возникающая из-за устаревшего исключения, должна быть воспроизводимой.
Проверьте метку времени всех сборок, на которые ссылается приложение.
Если метки времени любых сборок, на которые ссылается ссылка, позже метки времени последней компиляции приложения, значит приложение устарело. Если оно устарело, перекомпилируйте приложение с самыми последними сборками и при необходимости измените код.
Повторно запустите приложение, выполните действия, которые воспроизводят проблему, и убедитесь, что исключение не возникает.
Пример
Следующая программа иллюстрирует проблему: она сначала снижает доступность метода, а затем пытается получить доступ к этому методу в другой сборке без повторной компиляции. Сначала выполните компиляцию 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
Директива