Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

Upcasting و Downcasting

جزء من قسم Object Oriented Programming في رحلة C# على Coddy — الدرس 29 من 70.

عند العمل مع تسلسلات الوراثة الهرمية، غالباً ما تحتاج إلى التحويل بين الأنواع الأساسية والمشتقة. التحويل للأعلى (Upcasting) يحول النوع المشتق إلى نوعه الأساسي، بينما التحويل للأسفل (Downcasting) يقوم بالعكس.

التحويل التصاعدي (Upcasting) هو عملية ضمنية وآمنة دائمًا لأن الفئة المشتقة (derived class) مضمونة لاحتوائها على كل ما تحتويه الفئة الأساسية (base class):

Dog myDog = new Dog();
Animal animal = myDog;  // التحويل للأعلى (Upcasting) - ضمني، يعمل دائماً

يتطلب التحويل السفلي (Downcasting) تحويلاً صريحاً (explicit cast) ويمكن أن يفشل في وقت التشغيل (runtime) إذا لم يكن الكائن في الواقع من النوع الذي تقوم بالتحويل إليه:

Animal animal = new Dog();
Dog dog = (Dog)animal;  // Downcasting - يعمل لأنه في الحقيقة Dog

Animal cat = new Cat();
Dog wrong = (Dog)cat;   // يرمي InvalidCastException!

لإجراء عملية التحويل لأسفل (downcast) بأمان، استخدم الكلمة المفتاحية is للتحقق من النوع أولاً، أو استخدم as التي تُرجع null بدلاً من طرح استثناء (exception):

if (animal is Dog d)
{
    d.Bark();  // آمن - d متاح فقط إذا نجح التحقق
}

Dog maybeDog = animal as Dog;
if (maybeDog != null)
{
    maybeDog.Bark();
}

يُفضل نهج مطابقة الأنماط باستخدام is في لغة C# الحديثة لأنه يجمع بين التحقق من النوع والتحويل في خطوة واحدة، مما يجعل الكود الخاص بك أكثر أماناً ووضوحاً.

challenge icon

التحدي

سهل

لنقم ببناء نظام فحص للمركبات يوضح كيف تتيح لك عمليتا upcasting و downcasting العمل بمرونة مع الكائنات في تسلسل هرمي للوراثة. ستقوم بإنشاء أنواع مختلفة من المركبات وكتابة كود يحدد بأمان أنواع المركبات المحددة ويتفاعل معها.

ستقوم بتنظيم الكود الخاص بك عبر أربعة ملفات:

  • Vehicle.cs: قم بتعريف فئة أساسية باسم Vehicle في مساحة الأسماء Inspection. كل مركبة لها خاصية LicensePlate (سلسلة نصية) يتم تعيينها من خلال منشئ (constructor). قم بتضمين طريقة تسمى GetBasicInfo() تعيد "Vehicle: {LicensePlate}".
  • Car.cs: قم بتعريف فئة Car في مساحة الأسماء Inspection ترث من Vehicle. للسيارات خاصية إضافية هي NumberOfDoors (عدد صحيح). يقبل المنشئ كلاً من لوحة الترخيص وعدد الأبواب. أضف طريقة تسمى Honk() تعيد "{LicensePlate} honks: Beep beep!".
  • Motorcycle.cs: قم بتعريف فئة Motorcycle في مساحة الأسماء Inspection ترث من Vehicle. للدراجات النارية خاصية HasSidecar (قيمة منطقية). يقبل المنشئ لوحة الترخيص وحالة العربة الجانبية. أضف طريقة تسمى Rev() تعيد "{LicensePlate} revs: Vroom!".
  • Program.cs: في ملفك الرئيسي، ستقوم بإنشاء مركبات وممارسة كل من upcasting و downcasting الآمن. قم بإنشاء Car و Motorcycle باستخدام قيم الإدخال، ثم قم بتخزينهما في مصفوفة من مراجع Vehicle (upcasting). قم بالمرور عبر المصفوفة ولكل مركبة، اطبع معلوماتها الأساسية. ثم استخدم الكلمة المفتاحية is مع مطابقة النمط (pattern matching) للقيام بعملية downcast بأمان: إذا كانت Car، فاستدعِ Honk()؛ وإذا كانت Motorcycle، فاستدعِ Rev().

ستتلقى أربعة مدخلات:

  • لوحة ترخيص السيارة
  • عدد الأبواب
  • لوحة ترخيص الدراجة النارية
  • هل تحتوي على عربة جانبية (true أو false)

اطبع المخرجات بهذا التنسيق لكل مركبة في المصفوفة:

{GetBasicInfo() result}
{Honk() or Rev() result based on actual type}

على سبيل المثال، إذا كانت المدخلات هي ABC-123، و 4، و XYZ-789، و false، فيجب أن تكون المخرجات:

Vehicle: ABC-123
ABC-123 honks: Beep beep!
Vehicle: XYZ-789
XYZ-789 revs: Vroom!

لاحظ كيف يتم تخزين جميع المركبات كمراجع Vehicle (upcasting)، ولكن يمكنك اكتشاف أنواعها الحقيقية بأمان والوصول إلى الطرق الخاصة بكل نوع باستخدام صيغة مطابقة النمط is لعملية downcasting!

ورقة مرجعية

عند العمل مع التسلسلات الهرمية للوراثة، يقوم **التحويل للأعلى (upcasting)** بتحويل نوع مشتق إلى نوعه الأساسي، بينما يقوم **التحويل للأسفل (downcasting)** بتحويل نوع أساسي إلى نوع مشتق.

**التحويل للأعلى (Upcasting)** هو تحويل ضمني وآمن دائمًا:

Dog myDog = new Dog();
Animal animal = myDog;  // Upcasting - implicit, always works

يتطلب **التحويل للأسفل (Downcasting)** تحويلاً صريحًا ويمكن أن يفشل أثناء وقت التشغيل:

Animal animal = new Dog();
Dog dog = (Dog)animal;  // Downcasting - works because it's really a Dog

Animal cat = new Cat();
Dog wrong = (Dog)cat;   // Throws InvalidCastException!

**التحويل للأسفل الآمن** باستخدام الكلمة المفتاحية is مع مطابقة الأنماط (مفضل):

if (animal is Dog d)
{
    d.Bark();  // Safe - d is only available if check passes
}

**التحويل للأسفل الآمن** باستخدام الكلمة المفتاحية as (يرجع null إذا فشل التحويل):

Dog maybeDog = animal as Dog;
if (maybeDog != null)
{
    maybeDog.Bark();
}

جرّب بنفسك

using System;
using Inspection;

class Program
{
    public static void Main(string[] args)
    {
        // قراءة المدخلات
        string carPlate = Console.ReadLine();
        int numberOfDoors = Convert.ToInt32(Console.ReadLine());
        string motorcyclePlate = Console.ReadLine();
        bool hasSidecar = Convert.ToBoolean(Console.ReadLine());
        
        // TODO: إنشاء كائن Car باستخدام carPlate و numberOfDoors
        
        // TODO: إنشاء كائن Motorcycle باستخدام motorcyclePlate و hasSidecar
        
        // TODO: إنشاء مصفوفة من مراجع Vehicle تحتوي على كلا المركبتين (upcasting)
        
        // TODO: التكرار عبر المصفوفة ولكل مركبة:
        //   - طباعة نتيجة GetBasicInfo()
        //   - استخدام الكلمة المفتاحية 'is' مع مطابقة النمط (pattern matching) للقيام بعملية downcast بأمان:
        //     - إذا كانت Car، قم باستدعاء وطباعة Honk()
        //     - إذا كانت Motorcycle، قم باستدعاء وطباعة Rev()
    }
}
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس Object Oriented Programming