Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
A tükröződés lehetővé teszi az ismert adattípusok futásidőben történő vizsgálatát. A tükrözés lehetővé teszi az adattípusok számbavételét egy adott szerelvényben, és egy adott osztály vagy értéktípus tagjai felderíthetők. Ez attól függetlenül igaz, hogy a típust a fordításkor ismerték vagy hivatkozták-e. A reflektálás hasznos funkció a fejlesztés és a kódkezelő eszközök számára.
Vegye figyelembe, hogy a megadott szerelvénynév az erős névvel rendelkezik (lásd: Strong-Named szerelvények létrehozása és használata), amely tartalmazza a szerelvény verzióját, a kulturális beállításokat és az aláírási információkat. Vegye figyelembe, hogy annak a névtérnek a neve, amelyben az adattípus definiálva van, lekérhető az alaposztály nevével együtt.
A tükröződési funkciók elérésének leggyakoribb módja a GetType módszer. Ezt a módszert az adja meg System.Object, amelyből az összes szemétgyűjtési osztály származik.
Megjegyzés:
A Microsoft C++ fordítóval készült .exe-on csak akkor engedélyezett a Reflection használata, ha a .exe a /clr:pure vagy /clr:safe fordító beállításaival készült. A /clr:pure és /clr:safe fordítóbeállítások elavultak a Visual Studio 2015-ben, és nem érhetők el a Visual Studio 2017-ben. További információt a /clr (Common Language Runtime Compilation) című témakörben talál.
További információért, lásd: System.Reflection
Példa: GetType
A GetType metódus egy osztályobjektumra Type mutató mutatót ad vissza, amely az objektum alapjául szolgáló típust írja le. (A Type objektum nem tartalmaz példányspecifikus információkat.) Az egyik ilyen elem a típus teljes neve, amely a következőképpen jeleníthető meg:
Vegye figyelembe, hogy a típusnév tartalmazza a teljes hatókört, amelyben a típus definiálva van, beleértve a névteret is, és hogy a .NET szintaxisban jelenik meg, a hatókörfeloldási operátor pedig ponttal.
// 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());
}
full type name of 'sample string' is 'System.String'
Példa: dobozos értéktípusok
Az értéktípusok a GetType függvényhez is használhatók, de először be kell őket jelölni.
// 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());
}
type of i = 'System.Int32'
Példa: typeid
A metódushoz hasonlóan a GetTypetypeid operátor egy Type objektumra mutató mutatót ad vissza, így ez a kód a System.Int32 típusnevet jelzi. A típusnevek megjelenítése a tükröződés legalapvetőbb funkciója, de egy potenciálisan hasznosabb módszer az enumerált típusok érvényes értékeinek vizsgálata vagy felderítése. Ez a statikus Enum::GetNames függvénnyel végezhető el, amely egy sztringtömböt ad vissza, amelyek mindegyike szöveges formában tartalmaz enumerálási értéket. Az alábbi minta egy sztringtömböt kér le, amely a Beállítások (CLR) enumerálási értékeit írja le, és egy hurokban jeleníti meg őket.
Ha a Beállítások enumeráláshoz hozzáad egy negyedik lehetőséget, ez a kód újrafordítás nélkül jelenti az új beállítást, még akkor is, ha az enumerálás egy külön szerelvényben van definiálva.
// 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);
}
there are 3 options in enum 'Options'
0: Option1
1: Option2
2: Option3
value of 'o' is Option2
Példa: GetType-tagok és tulajdonságok
Az GetType objektum számos tagot és tulajdonságot támogat, amelyek egy típus vizsgálatára használhatók. Ez a kód a következő információk némelyikét kéri le és jeleníti meg:
// 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);
}
type information for 'String':
assembly name: mscorlib, Version=1.0.5000.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
namespace: System
base type: System.Object
is array: False
is class: True
Példa: típusok számbavétele
A reflexió lehetővé teszi a típusok felsorolását egy egységen belül, valamint az osztályokban lévő tagok felsorolását is. A funkció bemutatásához definiáljon egy egyszerű osztályt:
// 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; }
}
};
Példa: szerelvények ellenőrzése
Ha a fenti kód egy vcpp_reflection_6.dllnevű DLL-re van lefordítva, a szerelvény tartalmának vizsgálatához használhatja a visszaverődést. Ehhez az xref:System.Reflection.Assembly.Load%2A?displayProperty=nameWithType statikus tükröződési API-függvényt kell használnia a szerelvény betöltéséhez. Ez a függvény egy szerelvényobjektum címét adja vissza, amely ezután lekérdezhető a modulokról és a benne lévő típusokról.
Miután a visszatükrözési rendszer sikeresen betölti az assembly-t, a függvény egy Assembly.GetTypes objektumokat tartalmazó tömböt kér le. Minden tömbelem más típusú információkat tartalmaz, de ebben az esetben csak egy osztály van definiálva. Hurok használatával lekérdezzük a tömb minden elemének típusát a Type::GetMembers függvénnyel. Ez a függvény a MethodInfo objektumokat tartalmazó tömböt adja vissza, amelyek a tagfüggvényről, az adattagról vagy a típusban lévő tulajdonságról tartalmaznak információkat.
Vegye figyelembe, hogy a metódusok listája tartalmazza a TestClass-ban explicit módon definiált függvényeket és a System::Object osztálytól implicit módon öröklő függvényeket. Annak részeként, hogy nem a Visual C++ szintaxisban, hanem a .NET-ben van ismertetve, a tulajdonságok a get/set függvények által elért mögöttes adattagként jelennek meg. A get/set függvények normál metódusként jelennek meg ebben a listában. A tükröződést a közös nyelvi futtatókörnyezet támogatja, nem a Microsoft C++ fordítója.
Bár ezt a kódot egy ön által definiált szerelvény vizsgálatára használta, a .NET-szerelvények vizsgálatához is használhatja ezt a kódot. Ha például a TestAssemblyt mscorlib értékre módosítja, akkor megjelenik a mscorlib.dlldefiniált összes típus és módszer listája.
// 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);
}
Útmutató: Plug-In összetevőarchitektúra implementálása a Reflection használatával
Az alábbi példakód bemutatja, hogy a tükröződés egy egyszerű "beépülő modul" architektúra implementálásához használható. Az első lista az alkalmazás, a második pedig a beépülő modul. Az alkalmazás egy több dokumentuműrlap, amely a parancssori argumentumként megadott beépülő modul DLL-ben található űrlapalapú osztályok használatával tölti ki magát.
Az alkalmazás megkísérli betölteni a megadott szerelvényt a System.Reflection.Assembly.Load módszerrel. Ha sikerül, a System.Reflection.Assembly.GetTypes metódus segítségével a típusok felsorolásra kerülnek a kódtáron belül. Ezután a rendszer ellenőrzi, hogy az egyes típusok kompatibilisek-e a System.Type.IsAssignableFrom módszerrel. Ebben a példában a megadott szerelvényben található osztályokat az Form osztályból kell származtatnia, hogy beépülő modulnak minősüljön.
A kompatibilis osztályok ezután példányosítva lesznek a System.Activator.CreateInstance metódussal, amely argumentumként fogadja el az osztályt Type , és egy mutatót ad vissza egy új példánynak. Ezután minden új példány az űrlaphoz lesz csatolva, és megjelenik.
Vegye figyelembe, hogy a metódus nem fogadja el a Load fájlkiterjesztést tartalmazó szerelvényneveket. Az alkalmazás fő függvénye levágja a megadott bővítményeket, így az alábbi példa mindkét esetben működik.
Példaalkalmazás
Az alábbi kód határozza meg a beépülő modulokat elfogadó alkalmazást. Első argumentumként szerelvénynevet kell megadni. Ennek a szerelvénynek legalább egy nyilvános Form származtatott típust kell tartalmaznia.
// plugin_application.cpp
// compile with: /clr /c
#using <system.dll>
#using <system.drawing.dll>
#using <system.windows.forms.dll>
using namespace System;
using namespace System::Windows::Forms;
using namespace System::Reflection;
ref class PluggableForm : public Form {
public:
PluggableForm() {}
PluggableForm(Assembly^ plugAssembly) {
Text = "plug-in example";
Size = Drawing::Size(400, 400);
IsMdiContainer = true;
array<Type^>^ types = plugAssembly->GetTypes( );
Type^ formType = Form::typeid;
for (int i = 0 ; i < types->Length ; i++) {
if (formType->IsAssignableFrom(types[i])) {
// Create an instance given the type description.
Form^ f = dynamic_cast<Form^> (Activator::CreateInstance(types[i]));
if (f) {
f->Text = types[i]->ToString();
f->MdiParent = this;
f->Show();
}
}
}
}
};
int main() {
Assembly^ a = Assembly::LoadFrom("plugin_application.exe");
Application::Run(gcnew PluggableForm(a));
}
Példa beépülő modulok
Az alábbi kód három, a Form-ból származtatott osztályt határoz meg. Ha az eredményül kapott assembly neve az előző listában a futtathatónak lesz átadva, a rendszer mind a három osztályt felderíti és példányosít, annak ellenére, hogy a fordításkor mind ismeretlenek voltak a hosztoló alkalmazás számára.
// plugin_assembly.cpp
// compile with: /clr /LD
#using <system.dll>
#using <system.drawing.dll>
#using <system.windows.forms.dll>
using namespace System;
using namespace System::Windows::Forms;
using namespace System::Reflection;
using namespace System::Drawing;
public ref class BlueForm : public Form {
public:
BlueForm() {
BackColor = Color::Blue;
}
};
public ref class CircleForm : public Form {
protected:
virtual void OnPaint(PaintEventArgs^ args) override {
args->Graphics->FillEllipse(Brushes::Green, ClientRectangle);
}
};
public ref class StarburstForm : public Form {
public:
StarburstForm(){
BackColor = Color::Black;
}
protected:
virtual void OnPaint(PaintEventArgs^ args) override {
Pen^ p = gcnew Pen(Color::Red, 2);
Random^ r = gcnew Random( );
Int32 w = ClientSize.Width;
Int32 h = ClientSize.Height;
for (int i=0; i<100; i++) {
float x1 = w / 2;
float y1 = h / 2;
float x2 = r->Next(w);
float y2 = r->Next(h);
args->Graphics->DrawLine(p, x1, y1, x2, y2);
}
}
};
Útmutató: Adattípusok számbavétele a szerelvényekben a Reflection használatával
Az alábbi kód bemutatja a nyilvános típusok és tagok számbavételét a használatával System.Reflection.
Egy összeállítás nevének megadása után a helyi könyvtárban vagy a GAC-ban az alábbi kód megpróbálja megnyitni az összeállítást, és lekérni a leírásokat. Sikeres végrehajtás esetén minden típus megjelenik a nyilvános tagjaival együtt.
Vegye figyelembe, hogy System.Reflection.Assembly.Load nincs szükség fájlkiterjesztésre. Ezért a "mscorlib.dll" parancssori argumentumként való használata sikertelen lesz, míg az "mscorlib" használata a .NET-keretrendszer típusok megjelenítését eredményezi. Ha nincs megadva szerelvénynév, a kód észleli és jelenti az aktuális szerelvényen belüli típusokat (a kódból eredő EXE-t).
példa
// self_reflection.cpp
// compile with: /clr
using namespace System;
using namespace System::Reflection;
using namespace System::Collections;
public ref class ExampleType {
public:
ExampleType() {}
void Func() {}
};
int main() {
String^ delimStr = " ";
array<Char>^ delimiter = delimStr->ToCharArray( );
array<String^>^ args = Environment::CommandLine->Split( delimiter );
// replace "self_reflection.exe" with an assembly from either the local
// directory or the GAC
Assembly^ a = Assembly::LoadFrom("self_reflection.exe");
Console::WriteLine(a);
int count = 0;
array<Type^>^ types = a->GetTypes();
IEnumerator^ typeIter = types->GetEnumerator();
while ( typeIter->MoveNext() ) {
Type^ t = dynamic_cast<Type^>(typeIter->Current);
Console::WriteLine(" {0}", t->ToString());
array<MemberInfo^>^ members = t->GetMembers();
IEnumerator^ memberIter = members->GetEnumerator();
while ( memberIter->MoveNext() ) {
MemberInfo^ mi = dynamic_cast<MemberInfo^>(memberIter->Current);
Console::Write(" {0}", mi->ToString( ) );
if (mi->MemberType == MemberTypes::Constructor)
Console::Write(" (constructor)");
Console::WriteLine();
}
count++;
}
Console::WriteLine("{0} types found", count);
}