Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Refleksi memungkinkan jenis data yang diketahui diperiksa saat runtime. Pantulan memungkinkan enumerasi jenis data dalam rakitan tertentu, dan anggota kelas atau jenis nilai tertentu dapat ditemukan. Ini berlaku terlepas dari apakah jenis tersebut diketahui atau dirujuk pada waktu kompilasi. Hal ini menjadikan refleksi fitur yang berguna untuk alat manajemen pengembangan dan kode.
Perhatikan bahwa nama rakitan yang disediakan adalah nama kuat (lihat Membuat dan Menggunakan Rakitan dengan Nama Kuat), yang mencakup versi perakitan, budaya, dan informasi penandatanganan. Perhatikan juga bahwa nama ruang nama tempat tipe data ditentukan dapat diambil, bersama dengan nama kelas dasar.
Cara paling umum untuk mengakses fitur refleksi adalah melalui GetType metode . Metode ini disediakan oleh System.Object, yang menjadi asal bagi semua kelas yang dikelola oleh sistem pengumpulan sampah.
Catatan
Refleksi pada .exe yang dibangun dengan pengkompilasi Microsoft C++ hanya diperbolehkan jika .exe dibangun dengan opsi pengkompilasi /clr:pure atau /clr:safe . Opsi pengkompilasi /clr:pure dan /clr:safe tidak digunakan lagi di Visual Studio 2015 dan tidak tersedia di Visual Studio 2017. Lihat /clr (Kompilasi Runtime Bahasa Umum) untuk informasi selengkapnya.
Untuk informasi selengkapnya, lihat System.Reflection
Contoh: GetType
Metode GetType mengembalikan penunjuk ke Type objek kelas, yang menjelaskan jenis tempat objek didasarkan.
(Objek jenis tidak berisi informasi khusus instans apa pun.) Salah satu item tersebut adalah nama lengkap jenis, yang dapat ditampilkan sebagai berikut:
Perhatikan bahwa nama tipe menyertakan cakupan lengkap di mana tipe ditentukan, termasuk namespace, dan bahwa nama tersebut ditampilkan dalam sintaks .NET, dengan titik sebagai operator resolusi cakupan.
// 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'
Contoh: jenis nilai kotak
Jenis nilai juga dapat digunakan dengan GetType fungsi, tetapi harus dikotak terlebih dahulu.
// 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'
Contoh: typeid
Seperti pada metode GetType, operator typeid mengembalikan penunjuk ke objek Type, sehingga kode ini menampilkan nama Type System.Int32. Menampilkan nama jenis adalah fitur refleksi yang paling dasar, tetapi teknik yang berpotensi lebih berguna adalah memeriksa atau menemukan nilai yang valid untuk jenis enumerasi. Ini dapat dilakukan dengan menggunakan fungsi Enum::GetNames statis, yang mengembalikan array string, masing-masing berisi nilai enumerasi dalam bentuk teks. Sampel berikut mengambil kembali array string yang menjelaskan nilai-nilai enumerasi untuk enum Options (CLR) dan menampilkannya dalam perulangan.
Jika opsi keempat ditambahkan ke enumerasi Opsi , kode ini akan melaporkan opsi baru tanpa kompilasi ulang, bahkan jika enumerasi ditentukan dalam rakitan terpisah.
// 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
Contoh: Anggota dan properti GetType
Objek GetType mendukung sejumlah anggota dan properti yang dapat digunakan untuk memeriksa jenis. Kode ini mengambil dan menampilkan beberapa informasi ini:
// 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
Contoh: daftar jenis
Refleksi juga memungkinkan enumerasi jenis dalam rakitan dan anggota dalam kelas. Untuk menunjukkan fitur ini, tentukan kelas sederhana:
// 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; }
}
};
Contoh: inspeksi rakitan
Jika kode di atas dikompilasi ke dalam DLL yang disebut vcpp_reflection_6.dll, Anda kemudian dapat menggunakan pantulan untuk memeriksa konten rakitan ini. Ini melibatkan penggunaan fungsi API refleksi statis xref:System.Reflection.Assembly.Load%2A?displayProperty=nameWithType untuk memuat rakitan. Fungsi ini mengembalikan alamat objek Assembly yang kemudian dapat dikueri tentang modul dan jenis di dalamnya.
Setelah sistem refleksi berhasil memuat assembly, array objek Type diambil menggunakan fungsi Assembly.GetTypes. Setiap elemen array berisi informasi tentang jenis yang berbeda, meskipun dalam hal ini, hanya satu kelas yang ditentukan. Dengan menggunakan perulangan, setiap Type dalam array ini akan dikueri mengenai anggota tipe menggunakan Type::GetMembers. Fungsi ini mengembalikan array MethodInfo objects, setiap objek berisi informasi tentang fungsi anggota, anggota data, atau properti dalam tipe.
Perhatikan bahwa daftar metode mencakup fungsi yang secara eksplisit didefinisikan dalam TestClass dan fungsi yang secara implisit diwarisi dari kelas System::Object . Sebagai bagian dari yang dijelaskan dalam .NET daripada dalam sintaks Visual C++, properti muncul sebagai anggota data yang mendasar yang diakses oleh fungsi get/set. Fungsi get/set muncul dalam daftar ini sebagai metode reguler. Refleksi didukung melalui runtime bahasa umum, bukan oleh pengkompilasi Microsoft C++.
Meskipun Anda menggunakan kode ini untuk memeriksa rakitan yang Anda tentukan, Anda juga dapat menggunakan kode ini untuk memeriksa rakitan .NET. Misalnya, jika Anda mengubah TestAssembly menjadi mscorlib, maka Anda akan melihat daftar setiap jenis dan metode yang ditentukan dalam 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);
}
Cara: Menerapkan Arsitektur Komponen Plug-In menggunakan Pantulan
Contoh kode berikut menunjukkan penggunaan pantulan untuk mengimplementasikan arsitektur "plug-in" sederhana. Daftar pertama adalah aplikasi, dan yang kedua adalah plug-in. Aplikasi ini adalah form dokumen ganda yang menghasilkan kontennya sendiri menggunakan kelas berbasis formulir apa pun yang ditemukan di DLL plug-in yang disediakan sebagai argumen baris perintah.
Aplikasi mencoba memuat rakitan yang disediakan menggunakan System.Reflection.Assembly.Load metode . Jika berhasil, tipe di dalam rakitan didaftarkan menggunakan metode System.Reflection.Assembly.GetTypes. Setiap jenis kemudian diperiksa kompatibilitasnya menggunakan metode .System.Type.IsAssignableFrom Dalam contoh ini, kelas yang ditemukan dalam rakitan yang disediakan, harus berasal dari kelas Form untuk memenuhi syarat sebagai plug-in.
Kelas yang kompatibel kemudian dibuat dengan System.Activator.CreateInstance metode , yang menerima Type sebagai argumen dan mengembalikan pointer ke instans baru. Setiap instans baru kemudian dilampirkan ke formulir dan ditampilkan.
Perhatikan bahwa metode Load tidak menerima nama rakitan yang termasuk ekstensi file. Fungsi utama dalam aplikasi memangkas ekstensi yang disediakan, sehingga contoh kode berikut berfungsi dalam kedua kasus.
Contoh aplikasi
Kode berikut mendefinisikan aplikasi yang menerima plug-in. Nama rakitan harus disediakan sebagai argumen pertama. Rakitan ini harus berisi setidaknya satu tipe turunan publik Form.
// 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));
}
Contoh plugin
Kode berikut mendefinisikan tiga kelas yang berasal dari Form. Ketika nama assembly yang dihasilkan diteruskan ke executable dalam daftar sebelumnya, masing-masing dari ketiga kelas ini akan ditemukan dan diinstansiasi, terlepas dari kenyataan bahwa mereka semua tidak diketahui oleh aplikasi hosting pada waktu kompilasi kode.
// 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);
}
}
};
Cara Enumerasi Tipe Data dalam Assembly menggunakan Reflection
Kode berikut menunjukkan enumerasi jenis publik dan anggota menggunakan System.Reflection.
Diberikan nama rakitan, baik di direktori lokal maupun di GAC, kode di bawah ini coba membuka rakitan dan mengambil deskripsi. Jika berhasil, setiap jenis data ditampilkan dengan anggota publiknya.
Perhatikan bahwa System.Reflection.Assembly.Load mengharuskan untuk tidak menggunakan ekstensi file. Oleh karena itu, menggunakan "mscorlib.dll" sebagai argumen baris perintah akan gagal, sementara hanya menggunakan "mscorlib" akan menghasilkan tampilan jenis .NET Framework. Jika tidak ada nama rakitan yang disediakan, kode akan mendeteksi dan melaporkan jenis dalam rakitan saat ini (EXE yang dihasilkan dari kode ini).
Contoh
// 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);
}