توسيع C#: الخرافات والحقيقة حول خصائص الامتداد

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

خصائص الامتداد في C#: عندما تريدها ولا تستطيع (وكيف تتجاوز ذلك)



تخيل موقفًا: أنت تعمل مع مكتبة حيث تحتوي الفئة Person على خاصية FullName. كل شيء رائع، ولكن هناك مشكلة - تحتاج إلى إضافة خاصية محسوبة AgeInDays تحسب العمر بالأيام من تاريخ الميلاد. أنت معتاد على طرق الامتداد وتفكر: "لماذا لا نصنع خصائص امتداد؟"



ثم تذهب إلى Stack Overflow، وترى سؤالًا بآلاف المشاهدات: "هل تحتوي C# على خصائص امتداد؟" - وتقرأ الإجابة بخيبة أمل: "لا، غير مدعومة رسميًا". لكن لا تغلق علامة التبويب! في هذه المقالة، لن نناقش فقط سبب عدم وجودها، بل سنجد أيضًا طرقًا أنيقة لتجاوز ذلك لا تقل أداءً.



لماذا لا تضيف C# خصائص الامتداد؟ السياق التاريخي



لنبدأ بالأهم: خصائص الامتداد ليست نزوة، بل طلب طويل الأمد من المجتمع. في عام 2016، ظهر اقتراح على GitHub، لكنه لم يُنفذ حتى الآن. لماذا؟



  • التعقيد مع المترجم: على عكس الطرق، تحتوي الخصائص على أدوات getter و setter يجب ربطها بمثيل معين. توسيع هذا المنطق على مستوى بناء الجملة يتطلب تغييرات جذرية في المترجم.
  • التعارض مع المفهرسات: الخصائص والمفهرسات في C# مرتبطة ارتباطًا وثيقًا. إضافة خصائص الامتداد قد تخلق غموضًا.
  • أولوية الميزات الأخرى: ركز فريق C# على records و pattern matching و static abstract members (C# 11)، التي تقدم فائدة أكبر لمعظم السيناريوهات.


لكن غياب الدعم الرسمي ليس حكمًا بالإعدام. دعنا نرى كيف يحل المطورون ذوو الخبرة هذه المشكلة.



طرق الامتداد: أداتك الرئيسية (ولكن مع تفاصيل دقيقة)



الطريقة الأكثر وضوحًا هي استخدام طرق الامتداد بدلاً من الخصائص. بدلاً من person.AgeInDays، تكتب person.GetAgeInDays(). هذا يعمل، لكنه ينتهك مبدأ التوحيد: في بقية الكود، تستخدم الخصائص، وفجأة تستخدم طريقة.



public static class PersonExtensions{    public static int GetAgeInDays(this Person person)    {        return (DateTime.Now - person.BirthDate).Days;    }}

// الاستخدام:var age = person.GetAgeInDays(); // يعمل، لكنه غير جميل


العيب: يصبح الكود أقل قابلية للقراءة، خاصة في سلاسل استدعاءات LINQ. الميزة: هذا مجاني تمامًا من حيث الأداء - استدعاء طريقة الامتداد لا يختلف عن أي طريقة ثابتة عادية.



البديل رقم 1: المصانع الثابتة والفئات المساعدة



إذا كنت بحاجة إلى "خاصية" تُحسب بناءً على البيانات، يمكنك إنشاء فئة مساعدة ثابتة:



public static class PersonHelper{    public static int AgeInDays(Person person) => (DateTime.Now - person.BirthDate).Days;}

// الاستخدام:var age = PersonHelper.AgeInDays(person);


هذا أكثر صدقًا من طريقة الامتداد: من الواضح أنها دالة مساعدة. لكنها لا تزال ليست خاصية.



البديل رقم 2: السمات وتوليد الكود (Source Generators)



للسيناريوهات المعقدة (مثل إضافة خصائص إلى فئات من حزم NuGet)، يمكنك استخدام مولدات المصدر. ظهرت في .NET 5 وتسمح بتوليد الكود أثناء مرحلة التجميع. تكتب سمة، ويقوم المولد بإنشاء فئة جزئية بالخصائص المطلوبة.



[AutoExtensionProperty(typeof(Person), nameof(Person.BirthDate))]public partial class PersonExtensions{    // المولد سينشئ خاصية AgeInDays}

// الكود المُنشأ:public partial class PersonExt

المدونات

توصيات الكتب