Partilhar via


Tipos gerenciados (C++/CLI)

O Visual C++ permite o acesso a recursos do .NET por meio de tipos gerenciados, que fornecem suporte para recursos do Common Language Runtime e estão sujeitos às vantagens e restrições do tempo de execução.

Tipos gerenciados e a função principal

Quando se escreve uma aplicação usando /clr, os argumentos da função main() não podem ser de um tipo gerido.

Um exemplo de assinatura adequada é:

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

Equivalentes do .NET Framework a tipos nativos do C++

A tabela a seguir mostra as palavras-chave para tipos internos do Visual C++, que são aliases de tipos predefinidos no namespace System .

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

Para obter mais informações sobre a opção do compilador para padrão signed char ou unsigned char, consulte /J (Tipo padrão char é unsigned).

Questões de versão para tipos de valor aninhados em tipos nativos

Considere um módulo de assembly assinado (nome forte) usado para criar um assembly cliente. O componente contém um tipo de valor que é usado no cliente como o tipo para um membro de uma união nativa, uma classe ou uma matriz. Se uma versão futura do componente alterar o tamanho ou o layout do tipo de valor, o cliente deve ser recompilado.

Crie um arquivo de chave com sn.exe (sn -k mykey.snk).

Exemplo

Este é o exemplo do componente.

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

Este exemplo é o cliente:

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

O exemplo produz esta saída:

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

Observações

No entanto, se você adicionar outro membro a struct S in nested_value_types.cpp (por exemplo, double d;) e recompilar o componente sem também recompilar o cliente, o resultado será uma exceção não tratada (do tipo System.IO.FileLoadException).

Como testar a igualdade

No exemplo a seguir, um teste de igualdade que usa Extensões Geridas para C++ é baseado no que os handles se referem.

Exemplo

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

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

O IL para este programa mostra que o valor de retorno é implementado usando uma chamada para op_Equality.

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

Como diagnosticar e corrigir problemas de compatibilidade de montagem

Quando a versão de um assembly referenciada em tempo de compilação não corresponde à versão do assembly referenciada em tempo de execução, vários problemas podem ocorrer.

Quando um conjunto é compilado, outros conjuntos podem ser referenciados com a sintaxe #using. Durante a compilação, esses assemblies são acessados pelo compilador. As informações desses assemblies são usadas para tomar decisões de otimização.

No entanto, se o assembly referenciado for alterado e recompilado, recompile também o assembly de referência que depende dele. Caso contrário, as assemblagens poderão tornar-se incompatíveis. As decisões de otimização que eram válidas no início podem não estar corretas para a nova versão do assembly. Vários erros de tempo de execução podem ocorrer devido a essas incompatibilidades. Não há nenhuma exceção específica produzida nesses casos. A maneira como a falha é relatada no tempo de execução depende da natureza da alteração de código que causou o problema.

Esses erros não devem ser um problema em seu código de produção final, desde que todo o aplicativo seja reconstruído para a versão lançada do seu produto. As montagens liberadas ao público devem ser identificadas por um número de versão oficial, para que esses problemas sejam evitados. Para obter mais informações, consulte Assembly Versioning.

Para diagnosticar e corrigir um erro de incompatibilidade

Você pode encontrar exceções de tempo de execução ou outras condições de erro no código que faz referência a outro assembly. Se não for possível identificar outra causa, o problema pode ser uma montagem desatualizada.

  1. Primeiro, isole e reproduza a exceção ou outra condição de erro. Um problema que ocorre devido a uma exceção desatualizada deve ser reproduzível.

  2. Verifique o carimbo de data/hora de todos os assemblies referenciados em seu aplicativo.

  3. Se os carimbos de data/hora de quaisquer assemblies referenciados forem posteriores ao carimbo de data/hora da última compilação do aplicativo, o aplicativo estará desatualizado. Se estiver desatualizado, recompile seu aplicativo com os assemblies mais recentes e edite seu código, se necessário.

  4. Execute novamente o aplicativo, execute as etapas que reproduzem o problema e verifique se a exceção não ocorre.

Exemplo

O programa a seguir ilustra o problema: ele primeiro reduz a acessibilidade de um método e, em seguida, tenta acessar esse método em outro assembly sem recompilar. Compile changeaccess.cpp primeiro. É a montagem referenciada que será alterada. Em seguida, compile referencing.cpp. Deve compilar com sucesso. Em seguida, reduza a acessibilidade do método chamado. Recompile changeaccess.cpp com a opção /DCHANGE_ACCESSdo compilador . Faz com que o método access_me seja protected, em vez de public, de modo que não possa ser chamado fora de Test ou dos seus derivados. Sem recompilar referencing.exe, execute novamente o aplicativo. A MethodAccessException ocorre.

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

};

Aqui está a fonte para a assemblagem de referência:

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

Ver também

Programação .NET com C++/CLI (Visual C++)
Interoperabilidade com outras linguagens .NET (C++/CLI)
Tipos gerenciados (C++/CLI)
#using diretiva