الانعكاس في ++C

الانعكاس يسمح بفحص أنواع البيانات المعروفة في وقت التشغيل. الانعكاس يسمح بتعداد أنواع البيانات في تجميع،و يمكن اكتشاف أعضاء فئة محددة أو نوع قيمة. وينطبق هذا بغض النظر عن ما إذا كان النوع معروفاً أو مشاراً إليه في وقت التحويل البرمجي. يجعل هذا الانعكاسَ ميزة مفيدة لأدوات التطوير و إدارة التعليمات البرمجية.

لاحظ أن اسم التجميع الذي تم توفيره هو اسم قوى (راجع تجميعات مسماه بقوة )، يتضمن إصدار التجميع، البيانات الموروثة ومعلومات التوقيع. لاحظ أيضاً أن اسم مساحة اسم التي تم تعريف نوع بيانات فيها يمكن استرداده ، مع اسم الفئة الأساسية.

يعد الأسلوب الأكثر شيوعاً للوصول لميزات الانعكاس هو من خلال الأسلوب GetType . يتم توفير هذه الطريقة من قبل System::Object ، الذي تشتق منه كافة فئات تجميع البيانات المهملة.

يُسمح بالانعكاس على .exe تم بنؤءه ببرنامج التحويل البرمجي الخاص بـ Visual C++ إذا تم بناء الـ .exe بخيارات برنامج التحويل البرمجي /clr:pure أو /clr:safe . لمزيد من المعلومات، راجع /clr (التجميع وقت تشغيل اللغة العامة).

المواضيع في هذا المقطع:

لمزيد من المعلومات، راجع مساحة الاسم System.Reflection

مثال

أسلوب GetType يقوم بإرجاع مؤشر لكائن فئة Type التي تصف النوع الذي يستند إليه الكائن. (الكائن نوع لا يحتوي على أية معلومات خاصة بمثيل.) عنصر واحد مثل هذا هو الاسم الكامل للنوع والذي يمكن عرضه كما يلي:

لاحظ أن اسم النوع يتضمن النطاق الكامل الذي تم تعريف النوع فيه, بما في ذلك مساحة الاسم، ثم يتم عرضه في بناء جملة .NET، بنقطة كعامل دقة النطاق.

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

يمكن استخدام أنواع قيم مع دالة GetType بالإضافة إلى ذلك, ولكن يجب أن يتم تحويلها إلى كائن أولاً.

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

كما في أسلوب GetType ، عامل تشغيل typeid يقوم بإرجاع مؤشر لكائن نوع ،إذاً تشير هذة التعليمات البرمجية إلى اسم النوع System.Int32. عرض أسماء النوع هو الميزة الأكثر أساسية للانعكاس ولكن قد تكون التقنية الأكثر فائدة هي فحص أو اكتشاف القيم الصالحة لأنواع قائمة تعداد. يمكن إجراء ذلك عن طريق استخدام الدالة الثابتة Enum::GetNames ، والتي تقوم بإرجاع صفيفة سلاسل ، كل منهم تحتوي على قيمة تعداد في صورة النص. يسترد النموذج التالي صفيفة سلاسل تصف قيم قيمة التعداد لقائمة تعداد خيارات (CLR) و تعرضها في تكرار حلقي.

إذا تمت إضافة خيار رابع لقائمة تعداد خيارات، هذه التعليمات البرمجية ستقر الخيار الجديد دون إعادة التحويل البرمجي ، حتى إذا تم تعريف التعداد في تجميع منفصل.

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

كائن GetType يدعم عدداً من الأعضاء والخصائص التي يمكن استخدامها للتحقق من نوع. هذه التعليمة البرمجية تسترد وتعرض بعض من هذه المعلومات:

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

يسمح أيضاً الانعكاس بتعداد الأنواع داخل تجميع و الأعضاء داخل الفئات. لشرح هذه الميزة, قم بتعريف فئة بسيطة:

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

إذا تم ترجمة التعليمات البرمجية أعلاه إلى DLL يسمى vcpp_reflection_6.dll ، يمكنك استخدام الانعكاس لفحص محتويات هذا التجمع. هذا يتضمن استخدام دالة الانعكاس API الثابتة Assembly::Load لتحميل التجميع. هذة الدالة تقوم بإرجاع عنوان كائن التجميع الذي يمكن بعد ذلك أن ‏يُستعلم‬ منه حول الوحدات النمطية والأنواع داخله.

بمجرد تحميل نظام الانعكاس للتجميع بنجاح, يتم استرداد صفيفة من كائنات نوع من خلال دالة Assembly::GetTypes . يحتوي كل عنصر صفيف على معلومات حول نوع مختلف ، على الرغم من أنه في هذه الحالة، يتم تعريف فئة واحدة فقط. باستخدام تكرار حلقي ، تم الاستعلام من كل النوع في هذا الصفيف حول أعضاء النوع باستخدام دالة Type::GetMembers . هذه الدالة تقوم بإرجاع صفيف من الكائنات MethodInfo ، كل كائن يحتوي على معلومات حول دالة العضو أو عضو البيانات أو خاصية في النوع.

لاحظ أن قائمة الأساليب تتضمن دوال مُعرّفة بوضوح في TestClass و الدوال الموروثة ضمنيًا من فئة System::Object . كجزء من وصفها في .NET بدلاً من في بناء جملة Visual C++، تظهر الخصائص كعضو البيانات الأساسى الذي يتم الوصول إليه من قبل دالتي get/set . تظهر دالتي get/set في هذه القائمة كأساليب عادية. يتم دعم الانعكاس خلال لغة وقت التشغيل العامة، ليس عن طريق برنامج تحويل Visual C++ البرمجي.

على الرغم من أنه يمكنك استخدام هذه التعليمة البرمجية لفحص تجميع قمت بتعريفه ، يمكنك أيضاً استخدام هذه التعليمة البرمجية لفحص تجميعات .NET. على سبيل المثال، إذا قمت بتغيير TestAssembly إلى mscorlib، سوف ترى إذاً قائمة بكل أسلوب و نوع مُعرّفين في 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);
}

راجع أيضًا:

موارد أخرى

دليل البرمجة لـ NET.