الـ Attributes والـ Reflection
جزء من قسم البرمجة كائنية التوجه في رحلة C# على Coddy. الدرس 44 من 70.
السمات هي علامات بيانات وصفية تُرفق بعناصر التعليمات البرمجية مثل class وmethods أو الخصائص. وهي لا تغيّر طريقة تنفيذ التعليمات البرمجية مباشرةً، لكنها توفر معلومات يمكن قراءتها في وقت التشغيل. الانعكاس هو الآلية التي تقرأ هذه البيانات الوصفية.
تطبّق attribute بوضعها بين قوسين مربعين أعلى العنصر المستهدف:
[Obsolete("Use NewMethod instead")]
public void OldMethod() { }
[Serializable]
public class Person
{
public string Name { get; set; }
}يمكنك إنشاء سمات مخصصة عن طريق الوراثة من Attribute:
public class AuthorAttribute : Attribute
{
public string Name { get; }
public AuthorAttribute(string name) => Name = name;
}
[Author("John")]
public class Calculator { }تتيح لك الانعكاسية فحص الأنواع وقراءة السمات أثناء التشغيل باستخدام مساحة الأسماء System.Reflection:
Type type = typeof(Calculator);
var attr = type.GetCustomAttribute<AuthorAttribute>();
Console.WriteLine(attr.Name); // Johnيمكنك أيضًا اكتشاف methods وخصائص واستدعاؤها ديناميكيًا:
MethodInfo[] methods = type.GetMethods();
foreach (var method in methods)
Console.WriteLine(method.Name);تُشغّل السمات والانعكاس العديد من أطر العمل — إذ تستخدمها مكتبات التسلسل للتحكم في مخرجات JSON، وتستخدمها أطر الاختبار لاكتشاف methods الاختبار، كما تستخدمها حاويات حقن الاعتماديات لربط الخدمات تلقائيًا.
التحدي
سهللنَبْنِ نظامًا لاكتشاف المكونات الإضافية يستخدم السمات المخصصة وميزة الانعكاس للعثور تلقائيًا على الفئات الموسومة كمكونات إضافية ووصفها. يشبه هذا الطريقة التي تكتشف بها أُطر العمل الحقيقية المكونات أو أساليب الاختبار أو نقاط نهاية API في وقت التشغيل.
ستنظّم التعليمات البرمجية عبر ثلاثة ملفات:
PluginAttribute.cs: أنشئ سمة مخصصة تُسمىPluginAttributeفي مساحة الأسماءPluginSystem. يجب أن تقوم سمتك بما يلي:- ترث من
Attribute - تحتوي على خاصيتين للقراءة فقط:
Name(سلسلة نصية) وVersion(سلسلة نصية) - تقبل القيمتين كلتيهما من خلال مُنشئها
- ترث من
Plugins.cs: أنشئ عدة فئات للمكونات الإضافية في مساحة الأسماءPluginSystem. يجب تزيين بعضها باستخدامPluginAttribute، وألا تُزيَّن إحداها:ImageProcessor- موسومة باستخدام[Plugin("Image Processor", "1.0")]DataExporter- موسومة باستخدام[Plugin("Data Exporter", "2.5")]HelperUtility- غير موسومة بأي سمة (هذه مجرد فئة عادية)
Program.cs: في ملفك الرئيسي، استخدم الانعكاس لاكتشاف جميع الفئات التي تحتوي علىPluginAttribute. اطبع معلومات كل مكوّن إضافي يتم اكتشافه. ستحتاج إلى:- الحصول على جميع الأنواع من assembly الحالية
- فحص كل نوع بحثًا عن
PluginAttribute - استخراج الخاصيتين
NameوVersionللسمات وعرضهما
استخدم System.Reflection لفحص الأنواع واسترداد السمات المخصصة. تُرجع الطريقة GetCustomAttribute<T>() القيمة null إذا لم تكن السمة موجودة، لذا يمكنك استخدام ذلك لتصفية الفئات التي تمثل مكونات إضافية فعلية.
اطبع كل مكوّن إضافي يتم اكتشافه بهذا التنسيق، واحدًا في كل سطر:
Plugin: {Name} (v{Version})يجب طباعة المكونات الإضافية بالترتيب التالي: ImageProcessor أولًا، ثم DataExporter. يجب ألا تظهر الفئة HelperUtility في الناتج لأنها تفتقر إلى السمة.
الناتج المتوقع:
Plugin: Image Processor (v1.0)
Plugin: Data Exporter (v2.5)يوضح هذا التحدي كيف تستخدم أُطر العمل السمات كعلامات، وتستخدم الانعكاس لاكتشافها - وتدعم التقنية نفسها حاويات حقن التبعية ومكتبات التسلسل وأُطر عمل الاختبار!
جرّب بنفسك
using System;
using System.Reflection;
using PluginSystem;
class Program
{
public static void Main(string[] args)
{
// TODO: احصل على جميع الأنواع من التجميع الحالي
// تلميح: استخدم Assembly.GetExecutingAssembly().GetTypes()
// TODO: كرر عبر كل نوع وتحقق مما إذا كان يحتوي على PluginAttribute
// تلميح: استخدم type.GetCustomAttribute<PluginAttribute>()
// TODO: إذا كانت السمة موجودة، اطبع معلومات الإضافة بالتنسيق:
// Plugin: {Name} (v{Version})
}
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
1أساسيات OOP
الملفات الخارجيةNamespaces والتوجيهاتمقدمة في Classes و Objectsالكلمة المفتاحية 'this'Methods والمعاملاتFields مقابل PropertiesConstructorsObject Initializersمراجعة - آلة حاسبة بسيطة4الوراثة
صيغة الوراثة الأساسية (:)الكلمة المفتاحية 'base'الكلمات المفتاحية Virtual و Overrideالأصناف المختومة (Sealed Classes)الفئة الأساسية 'object'مراجعة - هيكلية الموظفين7ميزات متقدمة
تحميل العوامل (Operator Overloading)المفهرسات (Indexers (this[]))إعادة تعريف ()ToStringدوال التوسعة (Extension Methods)ملخص - Custom List2الخصائص والأعضاء الساكنة (Static Members)
الخصائص المطبقة تلقائيًا (Auto-Implemented Properties)خصائص القراءة فقط والكتابة فقطالحقول والدوال الساكنة (Static)الفئات الساكنة (Static Classes)الأعضاء ذات البنية التعبيرية (Expression-Bodied Members)5تعدد الأشكال والواجهات (Polymorphism & Interfaces)
تعدد الأشكال: وقت التجميع مقابل وقت التشغيلالواجهة مقابل الفئة المجردة (Abstract Class)الواجهات المتعددةالواجهات الصريحةUpcasting و Downcastingملخص - حاسبة الأشكال8مفاهيم البرمجة كائنية التوجه (OOP) المتقدمة
التركيب بدلاً من الوراثةالـ Generics (الأصناف والدوال)الـ Delegates والأحداثالـ Attributes والـ Reflectionواجهة IDisposable وجملة usingأساسيات Dependency Injectionتدرّب بنفسك: مترجم C# عبر الإنترنت