Reflexão em C++

Reflexão permite que os tipos de dados conhecidos ser inspecionadas em tempo de execução. Reflexão permite a enumeração de tipos de dados em um determinado assembly e os membros de um determinado tipo de classe ou o valor podem ser descobertos. Isso é verdadeiro independentemente do tipo era conhecido ou referenciado em tempo de compilação. Isso torna a reflexão um recurso útil para desenvolvimento e ferramentas de gerenciamento de código.

Observe que o nome do assembly fornecido é o nome forte (consulte Strong-Named Assemblies), que inclui a versão do assembly, cultura e informações de assinatura. Observe também que o nome do namespace no qual o tipo de dados é definido pode ser recuperado, junto com o nome da classe base.

A maneira mais comum para acessar os recursos de reflexão é através do GetType método. Este método é fornecido por System::Object, da qual derivam a todas as classes de coleta de lixo.

Reflexão em um. exe criado com o compilador Visual C++ é permitido se o arquivo. exe é construído com o /clr:pure ou /clr:safe Opções de compilador. See /CLR (common Language Runtime Compilation) for more information.

Tópicos nesta seção:

Para obter mais informações, consulte Namespace System. Reflection

Exemplo

O GetType método retorna um ponteiro para uma Type o objeto de classe, que descreve o tipo ao quando o objeto é baseado. (O tipo de objeto não contém qualquer informação específica de instância.) Um desses itens é o nome completo do tipo, que pode ser exibido como segue:

Observe que o nome do tipo inclui o escopo completo no qual o tipo é definido, incluindo o namespace, e que ele seja exibido na.NET sintaxe com um ponto como o operador de resolução de escopo.

// vcpp_reflection.cpp
// compile with: /clr
using namespace System;
int main() {
   String ^ s = "sample string";
   Console::WriteLine("full type name of '{0}' is '{1}'", s, s->GetType());
}
  

Tipos de valor podem ser usados com o GetType funcionar bem, mas deve ser box primeiro.

// vcpp_reflection_2.cpp
// compile with: /clr
using namespace System;
int main() {
   Int32 i = 100; 
   Object ^ o = i;
   Console::WriteLine("type of i = '{0}'", o->GetType());
}
  

Como ocorre com o GetType método, o typeid operador retorna um ponteiro para uma tipo de object, portanto, esse código indica o nome do tipo Int32. Exibindo nomes de tipo é o recurso mais básico de reflexão, mas é de uma técnica potencialmente mais útil inspecionar ou descobrir os valores válidos para os tipos enumerados. Isso pode ser feito usando-se estática Enum::GetNames funcionar, que retorna uma matriz de seqüências de caracteres, cada uma contendo um valor de enumeração na forma de texto. O exemplo a seguir recupera uma matriz de seqüências de caracteres que descreve os valores de enumeração do valor para o Opções (CLR) enum e os exibe em um loop.

Se uma quarta opção é adicionada para o Opções enumeração, esse código relatará a nova opção sem recompilação, mesmo se a enumeração é definida em um assembly separado.

// vcpp_reflection_3.cpp
// compile with: /clr
using namespace System;

enum class Options {   // not a native enum
   Option1, Option2, Option3
};

int main() {
   array<String^>^ names = Enum::GetNames(Options::typeid);

   Console::WriteLine("there are {0} options in enum '{1}'", 
               names->Length, Options::typeid);

   for (int i = 0 ; i < names->Length ; i++)
      Console::WriteLine("{0}: {1}", i, names[i]);

   Options o = Options::Option2;
   Console::WriteLine("value of 'o' is {0}", o);
}
  

O GetType objeto oferece suporte a um número de membros e propriedades que podem ser usadas para examinar um tipo. Este código recupera e exibe algumas dessas informações:

// vcpp_reflection_4.cpp
// compile with: /clr
using namespace System;
int main() {
   Console::WriteLine("type information for 'String':");
   Type ^ t = String::typeid;

   String ^ assemblyName = t->Assembly->FullName;
   Console::WriteLine("assembly name: {0}", assemblyName);

   String ^ nameSpace = t->Namespace;
   Console::WriteLine("namespace: {0}", nameSpace);

   String ^ baseType = t->BaseType->FullName;
   Console::WriteLine("base type: {0}", baseType);

   bool isArray = t->IsArray;
   Console::WriteLine("is array: {0}", isArray);

   bool isClass = t->IsClass;
   Console::WriteLine("is class: {0}", isClass);
}
  

Reflexão também permite a enumeração dos membros nas classes e tipos dentro de um assembly. Para demonstrar esse recurso, defina uma classe simples:

// vcpp_reflection_5.cpp
// compile with: /clr /LD
using namespace System;
public ref class TestClass {
   int m_i;
public:
   TestClass() {}
   void SimpleTestMember1() {}
   String ^ SimpleMember2(String ^ s) { return s; } 
   int TestMember(int i) { return i; }
   property int Member {
      int get() { return m_i; }
      void set(int i) { m_i = i; }
   }
};

Se o código acima é compilado em uma DLL chamada vcpp_reflection_6.dll, você pode usar reflexão para inspecionar o conteúdo desse assembly. Isso envolve usando a função de API de reflexão estática Assembly::Load para carregar o assembly. Esta função retorna o endereço de um Assembly o objeto que pode ser consultado sobre os módulos e os tipos de dentro.

Depois que o sistema de reflexão com êxito carrega o assembly, uma matriz de tipo de objetos são recuperados com o Assembly::GetTypes função. Cada elemento da matriz contém informações sobre um tipo diferente, embora nesse caso, somente uma classe é definida. Usando um loop, cada tipo de nessa matriz é consultado sobre os membros de tipo usando a Type::GetMembers função. Esta função retorna uma matriz de MethodInfo objetos, cada objeto que contém informações sobre a função de membro, o membro de dados ou a propriedade no tipo.

Observe que a lista de métodos inclui as funções explicitamente definidas em TestClass e as funções herdadas implicitamente da System::Object classe. Como parte do que está sendo descrito.NET em vez de na sintaxe do Visual C++, as propriedades aparecem como o membro de dados subjacente, acessado pelas funções get/set. As funções get/set aparecem nesta lista, como métodos regulares. Reflexão é suportado pelo common language runtime, não pelo compilador do Visual C++.

Embora você usou esse código para inspecionar um assembly que você definiu, você também pode usar este código para inspecionar.NET assemblies. Por exemplo, se você alterar o TestAssembly para mscorlib, você verá uma listagem de cada tipo e o método definido no mscorlib. dll.

// vcpp_reflection_6.cpp
// compile with: /clr
using namespace System;
using namespace System::IO;
using namespace System::Reflection;
int main() {
   Assembly ^ a = nullptr;
   try {
      // load assembly -- do not use file extension
      // will look for .dll extension first
      // then .exe with the filename
      a = Assembly::Load("vcpp_reflection_5");
   }
   catch (FileNotFoundException ^ e) {
      Console::WriteLine(e->Message);
      return -1;
   }

   Console::WriteLine("assembly info:");
   Console::WriteLine(a->FullName);
   array<Type^>^ typeArray = a->GetTypes();

   Console::WriteLine("type info ({0} types):", typeArray->Length);

   int totalTypes = 0;
   int totalMembers = 0;
   for (int i = 0 ; i < typeArray->Length ; i++) {
      // retrieve array of member descriptions
      array<MemberInfo^>^ member = typeArray[i]->GetMembers();

      Console::WriteLine("  members of {0} ({1} members):", 
      typeArray[i]->FullName, member->Length);
      for (int j = 0 ; j < member->Length ; j++) {
         Console::Write("       ({0})", 
         member[j]->MemberType.ToString() );
         Console::Write("{0}  ", member[j]);
         Console::WriteLine("");
         totalMembers++;
      }
      totalTypes++;
   }
   Console::WriteLine("{0} total types, {1} total members",
   totalTypes, totalMembers);
}

Consulte também

Outros recursos

.Guia de programação NET