Aracılığıyla paylaş


Yansıma (C++/CLI)

Yansıma, bilinen veri türlerinin çalışma zamanında denetlenmesini sağlar. Yansıma, belirli bir derlemedeki veri türlerinin sabitlenmesine olanak tanır ve belirli bir sınıfın veya değer türünün üyeleri bulunabilir. Bu, türün bilinen veya derleme zamanında başvurulup başvurulmadığına bakılmaksızın geçerlidir. Bu, yansımayı geliştirme ve kod yönetimi araçları için kullanışlı bir özellik haline getirir.

Sağlanan derleme adının, derleme sürümü, kültür ve imzalama bilgilerini içeren tanımlayıcı ad olduğunu unutmayın (bkz . Tanımlayıcı Adlandırılmış Derlemeler Oluşturma ve Kullanma). Veri türünün tanımlandığı ad alanının adının yanı sıra temel sınıfın adının alınabileceğini de unutmayın.

Yansıma özelliklerine erişmenin en yaygın yolu yöntemidir GetType . Bu yöntem, tüm çöp toplama sınıflarının türetildiği tarafından System.Objectsağlanır.

Not

Microsoft C++ derleyicisi ile oluşturulan bir .exe yansımaya yalnızca .exe /clr:pure veya /clr:safe derleyici seçenekleriyle derlendiğinde izin verilir. /clr:pure ve /clr:safe derleyici seçenekleri Visual Studio 2015'te kullanım dışıdır ve Visual Studio 2017'de kullanılamaz. Daha fazla bilgi için bkz. /clr (Ortak Dil Çalışma Zamanı Derlemesi).

Daha fazla bilgi için bkz. System.Reflection.

Örnek: GetType

GetType yöntemi, nesnenin temel aldığı türü açıklayan bir sınıf nesnesine yönelik bir Type işaretçi döndürür. (Tür nesnesi örneğe özgü herhangi bir bilgi içermiyor.) Bu tür öğelerden biri türün tam adıdır ve aşağıdaki gibi görüntülenebilir:

Tür adının ad alanı dahil olmak üzere türün tanımlandığı tam kapsamı içerdiğini ve kapsam çözümleme işleci olarak nokta ile .NET söz diziminde görüntülendiğini unutmayın.

// 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'

Örnek: kutulanmış değer türleri

Değer türleri işlevle GetType birlikte de kullanılabilir, ancak önce kutulanmalıdır.

// 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'

Örnek: typeid

yönteminde GetType olduğu gibi, typeid işleci bir Type nesnesine bir işaretçi döndürür, bu nedenle bu kod System.Int32 tür adını gösterir. Tür adlarını görüntülemek, yansımanın en temel özelliğidir, ancak potansiyel olarak daha kullanışlı bir teknik, numaralandırılmış türler için geçerli değerleri incelemek veya bulmaktır. Bu, her biri metin biçiminde bir numaralandırma değeri içeren bir dize dizisi döndüren statik Enum::GetNames işlevi kullanılarak yapılabilir. Aşağıdaki örnek, Seçenekler (CLR) sabit listesi için değer numaralandırma değerlerini açıklayan bir dize dizisi alır ve bunları bir döngüde görüntüler.

Seçenekler sabit listesi'ne dördüncü bir seçenek eklenirse, numaralandırma ayrı bir derlemede tanımlansa bile bu kod yeniden derleme olmadan yeni seçeneği bildirir.

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

Örnek: GetType üyeleri ve özellikleri

GetType nesnesi, bir türü incelemek için kullanılabilecek bir dizi üye ve özelliği destekler. Bu kod bu bilgilerden bazılarını alır ve görüntüler:

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

Örnek: türlerin sabit listesi

Yansıma ayrıca bir derleme içindeki türlerin ve sınıflar içindeki üyelerin listelenmesini sağlar. Bu özelliği göstermek için basit bir sınıf tanımlayın:

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

Örnek: derlemelerin incelenmesi

Yukarıdaki kod vcpp_reflection_6.dll adlı bir DLL'de derlenmişse, bu derlemenin içeriğini incelemek için yansımayı kullanabilirsiniz. Bu, derlemeyi yüklemek için xref:System.Reflection.Assembly.Load%2A?displayProperty=nameWithType statik yansıma API'sinin kullanılmasını içerir. Bu işlev, içindeki modüller ve türler hakkında sorgulanabilen bir Assembly nesnesinin adresini döndürür.

Yansıma sistemi derlemeyi başarıyla yükledikten sonra, işleviyle bir Assembly.GetTypes Tür nesneleri dizisi alınır. Her dizi öğesi farklı bir tür hakkında bilgi içerir, ancak bu durumda yalnızca bir sınıf tanımlanır. Döngü kullanıldığında, bu dizideki her Tür Type::GetMembers işlevi kullanılarak tür üyeleri hakkında sorgulanır. Bu işlev, her nesne türündeki üye işlev, veri üyesi veya özellik hakkında bilgi içeren bir MethodInfo nesneleri dizisi döndürür.

Yöntem listesinin, TestClass'ta açıkça tanımlanan işlevleri ve System::Object sınıfından örtük olarak devralınan işlevleri içerdiğini unutmayın. Özellikler, Visual C++ söz dizimi yerine .NET'te açıklanmanın bir parçası olarak get/set işlevleri tarafından erişilen temel veri üyesi olarak görünür. Get/set işlevleri bu listede normal yöntemler olarak görünür. Yansıma, Microsoft C++ derleyicisi tarafından değil ortak dil çalışma zamanı aracılığıyla desteklenir.

Tanımladığınız bir derlemeyi incelemek için bu kodu kullansanız da, .NET derlemelerini incelemek için de bu kodu kullanabilirsiniz. Örneğin, TestAssembly'yi mscorlib olarak değiştirirseniz, mscorlib.dll'de tanımlanan her tür ve yöntemin listesini görürsünüz.

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

Nasıl yapılır: Yansıma Kullanarak Eklenti Bileşen Mimarisi Uygulama

Aşağıdaki kod örnekleri basit bir "eklenti" mimarisi uygulamak için yansıma kullanımını göstermektedir. İlk liste uygulama, ikinci liste ise eklentidir. Uygulama, komut satırı bağımsız değişkeni olarak sağlanan eklenti DLL'sinde bulunan form tabanlı sınıfları kullanarak kendisini dolduran birden çok belge formudur.

Uygulama, yöntemini kullanarak sağlanan derlemeyi System.Reflection.Assembly.Load yüklemeyi dener. Başarılı olursa, derleme içindeki türler yöntemi kullanılarak System.Reflection.Assembly.GetTypes numaralandırılır. Ardından her tür, yöntemi kullanılarak uyumluluk açısından denetlendi System.Type.IsAssignableFrom . Bu örnekte, sağlanan derlemede bulunan sınıfların eklenti olarak nitelenebilmesi için sınıfından Form türetilmesi gerekir.

Uyumlu sınıflar daha sonra bir bağımsız değişken olarak kabul Type eden ve yeni bir örneğe bir işaretçi döndüren yöntemiyle System.Activator.CreateInstance örneği oluşturulur. Her yeni örnek forma eklenir ve görüntülenir.

yönteminin dosya uzantısını Load içeren derleme adlarını kabul etmediğini unutmayın. Uygulamadaki ana işlev sağlanan uzantıları kırpdığından aşağıdaki kod örneği her iki durumda da çalışır.

Örnek uygulama

Aşağıdaki kod, eklentileri kabul eden uygulamayı tanımlar. İlk bağımsız değişken olarak bir derleme adı sağlanmalıdır. Bu derleme en az bir genel Form türetilmiş tür içermelidir.

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

Örnek eklentiler

Aşağıdaki kod, öğesinden Formtüretilen üç sınıfı tanımlar. Sonuçta elde edilen derleme adının adı önceki listede yürütülebilir dosyaya geçirildiğinde, derleme zamanında barındırma uygulaması tarafından bilinmelerine rağmen bu üç sınıfın her biri bulunur ve örneği oluşturulur.

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

Nasıl yapılır: Yansıma Kullanarak Derlemelerdeki Veri Türlerini Listeleme

Aşağıdaki kod, kullanan System.Reflectiongenel türlerin ve üyelerin numaralandırmasını gösterir.

Yerel dizinde veya GAC'de bir derlemenin adı verüldüğünde, aşağıdaki kod derlemeyi açmayı ve açıklamaları almayı dener. Başarılı olursa, her tür kendi genel üyeleriyle birlikte görüntülenir.

System.Reflection.Assembly.Load Hiçbir dosya uzantısının kullanılmadığını unutmayın. Bu nedenle, komut satırı bağımsız değişkeni olarak "mscorlib.dll" kullanılması başarısız olurken, yalnızca "mscorlib" kullanıldığında .NET Framework türlerinin görüntülenmesine neden olur. Derleme adı sağlanmadıysa, kod geçerli derlemedeki türleri (bu koddan kaynaklanan EXE) algılar ve bildirir.

Örnek

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

Ayrıca bkz.