Sdílet prostřednictvím


Reflexe v C++

Reflexe umožňuje, aby byly známé datové typy zkoumány v době běhu. Reflexe umožňuje výčet datových typů v daném sestavení a mohou být zjištěny členy dané třídy nebo typu hodnoty. To platí bez ohledu na to, zda byl typ známý nebo odkazovaný v době kompilace. Díky tomu je reflexe užitečná funkce pro vývojové nástroje a nástroje pro správu kódu.

Všimněte si, že název sestavení, zadaný silném názvu (viz Silně pojmenovaná sestavení), zahrnuje verzi sestavení, jazykovou verzi a podepisovací informace. Všimněte si také, že název oboru názvů, ve kterém je datový typ definován, může být načten společně s názvem bázové třídy.

Nejběžnější způsob přístupu k funkcím reflexe je prostřednictvím metody GetType. Tato metoda je poskytována System::Object, z něhož jsou odvozeny všechny třídy, shromažďované uvolňováním paměti.

Reflexe na .exe, vytvořeném pomocí kompilátoru Visual C++ je povolena, pokud je .exe sestaveno s volbami kompilátoru /clr:pure nebo /clr:safe. Další informace naleznete v tématu /clr (Common Language Runtime Compilation).

Témata v tomto oddílu:

Pro další informace si prohlédněte Obor názvů System.Reflection

Příklad

Metoda GetType vrací ukazatel na objekt třídy Type, který popisuje typ, na kterém je objekt založen. (Objekt Type neobsahuje žádné informace specifické pro instanci.) Jedna položka je celé jméno typu, které lze zobrazit takto:

Všimněte si, že název typu zahrnuje úplný obor, ve kterém je typ definován, včetně oboru názvů, a že je zobrazen v syntaxi .NET, s tečkou jako operátorem rozlišení oboru.

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

Typy hodnot lze také použít s funkcí GetType, ale musí být nejprve zabaleny.

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

Jako metoda GetType, operátor typeid vrací ukazatel na objekt Type, takže tento kód označuje název typu System.Int32. Zobrazování názvů typů je nejzákladnější funkcí reflexe, ale potenciálně užitečnější technikou je zkoumání nebo objevování platných hodnot pro výčtové typy. To lze provést pomocí statické funkce Enum::GetNames, která vrací pole řetězců, kde každá položka obsahuje hodnotu výčtu v textové podobě. Následující příklad načte pole řetězců, které popisuje hodnoty výčtu hodnoty pro výčet Options (CLR) a zobrazí je ve smyčce.

Pokud bude do výčtu Options přidána čtvrtá volba, tento kód bude hlásit novou možnost bez rekompilace i v případě, že je výčet definován v samostatném sestavení.

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

Objekt GetType podporuje mnoho členů a vlastností, které lze použít k prozkoumání typu. Tento kód načte a zobrazí některé z těchto informací:

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

Reflexe také umožňuje výčet typů v rámci sestavení a členů v rámci třídy. Pro ukázku této funkce si definujte jednoduchou třídu:

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

Pokud bude výše uvedený kód zkompilován do knihovny DLL s názvem vcpp_reflection_6.dll, můžete využít reflexe pro zkoumání obsahu tohoto sestavení. To zahrnuje použití statická funkce rozhraní API reflexe Assembly::Load pro načtení sestavení. Tato funkce vrací adresu objektu Assembly, který může být dotazován na informace o jeho modulech a typech.

Jakmile systém reflexe úspěšně načte sestavení, je získáno pole objektů Type pomocí funkce Assembly::GetTypes. Každý element pole obsahuje informace o jiném typu, i když v tomto případě je definována pouze jedna třída. Pomocí smyčky je každý Type tohoto pole dotazován na členy typu pomocí funkce Type::GetMembers. Tato funkce vrací pole objektů MethodInfo, kde každý objekt obsahuje informace o členské funkci, datovém členu nebo vlastnosti v typu.

Všimněte si, že seznam metod zahrnuje funkce explicitně definované v TestClass a funkce implicitně zděděné ze třídy System::Object. Jako součást toho, že jsou popsány v syntaxi .NET, nikoli Visual C++, objeví se vlastnosti jako nadřazené datové členy, přistupované pomocí funkcí get/set. Funkce get/set jsou v tomto seznamu uvedeny jako běžné metody. Reflexe je podporována napříč modulem CLR (Common Language Runtime), nikoli kompilátorem Visual C++.

I když jste tento kód používali pro zkoumání sestavení, které jste definovali, můžete tento kód použít také pro zkoumání sestavení .NET. Změníte-li například TestAssembly na mscorlib, pak se zobrazí seznam všech typů a metod, které jsou definovány v 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);
}

Viz také

Další zdroje

Průvodce programováním .NET