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# الحديثة لأنه يجمع بين التحقق من النوع والتحويل في خطوة واحدة، مما يجعل الكود الخاص بك أكثر أماناً ووضوحاً.
التحدي
سهللنقم ببناء نظام فحص للمركبات يوضح كيف تتيح لك عمليتا 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()
}
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس Object Oriented Programming
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