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

الكلمات المفتاحية Virtual و Override

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

عندما ترث فئة مشتقة دالة ما، قد ترغب أحياناً في تغيير طريقة سلوك هذه الدالة تماماً. تعمل الكلمتان المفتاحيتان virtual و override معاً لجعل هذا ممكناً بطريقة محكومة.

قم بتمييز الطريقة كـ virtual في الفئة الأساسية للإشارة إلى أنه يُسمح للفئات المشتقة باستبدال تنفيذها:

public class Animal
{
    public virtual void Speak()
    {
        Console.WriteLine("Some sound");
    }
}

public class Dog : Animal
{
    public override void Speak()
    {
        Console.WriteLine("Woof!");
    }
}

تخبر الكلمة المفتاحية override في الفئة المشتقة (derived class) المترجم بأنك تقوم باستبدال الطريقة الأساسية (base method) عن قصد. وبدون وجود virtual في الطريقة الأساسية، لا يمكنك استخدام override.

تظهر القوة الحقيقية عندما تستخدم مرجعاً من الفئة الأساسية (base class) للإشارة إلى كائن مشتق (derived object):

Animal myPet = new Dog();
myPet.Speak();  // الناتج: Woof!

على الرغم من أن myPet تم التصريح عنه كـ Animal، إلا أن C# يستدعي نسخة Dog من Speak(). يسمى هذا تعدد الأشكال في وقت التشغيل (runtime polymorphism) - تعتمد الطريقة الفعلية التي يتم استدعاؤها على النوع الحقيقي للكائن، وليس على النوع المصرح به للمتغير.

لا يزال بإمكانك الوصول إلى التنفيذ الأساسي باستخدام base.Speak() داخل التجاوز (override) الخاص بك إذا كنت ترغب في توسيع السلوك بدلاً من استبداله بالكامل.

challenge icon

التحدي

سهل

لنقم ببناء نظام إشعارات يوضح كيف يمكن للفئات المشتقة تجاوز سلوك الفئة الأساسية تماماً باستخدام الكلمات المفتاحية virtual و override، مع إظهار قوة تعدد الأشكال في وقت التشغيل (runtime polymorphism).

ستقوم بإنشاء ثلاثة ملفات لتنظيم الكود الخاص بك:

  • Notification.cs: قم بتعريف فئة Notification داخل مساحة الأسماء Alerts. تمثل هذه الفئة الأساسية إشعاراً عاماً مع خاصية Message (سلسلة نصية) ومنشئ (constructor) يقوم بتعيينها. قم بتضمين تابع virtual يسمى Send() يعيد القيمة "Sending notification: {Message}".
  • EmailNotification.cs: قم بتعريف فئة EmailNotification داخل مساحة الأسماء Alerts التي ترث من Notification. أضف خاصية Recipient (سلسلة نصية) ومنشئاً يقبل كل من الرسالة والمستلم (استخدم base لتمرير الرسالة). قم بعمل override للتابع Send() ليعيد "Emailing {Recipient}: {Message}".
  • SmsNotification.cs: قم بتعريف فئة SmsNotification داخل مساحة الأسماء Alerts التي ترث أيضاً من Notification. أضف خاصية PhoneNumber (سلسلة نصية) ومنشئاً يقبل كل من الرسالة ورقم الهاتف. قم بعمل override للتابع Send() ليعيد "SMS to {PhoneNumber}: {Message}".
  • Program.cs: في ملفك الرئيسي، قم بإنشاء مثيلات (instances) من جميع أنواع الإشعارات الثلاثة باستخدام قيم الإدخال. ثم وضح تعدد الأشكال في وقت التشغيل عن طريق تخزين الثلاثة في متغيرات من نوع Notification واستدعاء Send() لكل منها.

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

  • رسالة الإشعار
  • عنوان البريد الإلكتروني للمستلم
  • رقم الهاتف لرسالة SMS

اطبع نتيجة استدعاء Send() لكل إشعار، مخزنة كمرجع للفئة الأساسية:

{base notification Send() result}
{email notification Send() result}
{sms notification Send() result}

على سبيل المثال، إذا كانت المدخلات هي Meeting at 3pm، و alice@email.com، و 555-1234، يجب أن يكون المخرج:

Sending notification: Meeting at 3pm
Emailing alice@email.com: Meeting at 3pm
SMS to 555-1234: Meeting at 3pm

لاحظ كيف أنه على الرغم من تخزين الثلاثة كمتغيرات من نوع Notification، إلا أن كل واحد منها يستدعي نسخته الخاصة التي تم تجاوزها من Send(). هذا هو تعدد الأشكال في وقت التشغيل أثناء العمل!

ورقة مرجعية

استخدم الكلمة المفتاحية virtual في الفئة الأساسية (base class) لتمييز الطريقة (method) التي يمكن للفئات المشتقة (derived classes) تجاوزها:

public class Animal
{
    public virtual void Speak()
    {
        Console.WriteLine("Some sound");
    }
}

استخدم الكلمة المفتاحية override في الفئة المشتقة لاستبدال تنفيذ الطريقة في الفئة الأساسية:

public class Dog : Animal
{
    public override void Speak()
    {
        Console.WriteLine("Woof!");
    }
}

يحدث تعدد الأشكال في وقت التشغيل (Runtime polymorphism) عندما يحمل مرجع الفئة الأساسية كائناً مشتقاً - تعتمد الطريقة الفعلية التي يتم استدعاؤها على النوع الحقيقي للكائن، وليس على النوع المعلن للمتغير:

Animal myPet = new Dog();
myPet.Speak();  // Output: Woof!

يمكنك الوصول إلى تنفيذ الفئة الأساسية داخل التجاوز (override) باستخدام base:

public override void Speak()
{
    base.Speak();  // يستدعي نسخة الفئة الأساسية
    Console.WriteLine("Woof!");
}

جرّب بنفسك

using System;
using Alerts;

class Program
{
    public static void Main(string[] args)
    {
        // قراءة المدخلات
        string message = Console.ReadLine();
        string email = Console.ReadLine();
        string phone = Console.ReadLine();

        // TODO: إنشاء مثيلات (instances) لجميع أنواع الإشعارات الثلاثة
        // تخزينها في متغيرات من نوع Notification لتوضيح تعدد الأشكال (polymorphism)
        
        // TODO: إنشاء Notification أساسي
        Notification baseNotification;
        
        // TODO: إنشاء EmailNotification (مخزن كنوع Notification)
        Notification emailNotification;
        
        // TODO: إنشاء SmsNotification (مخزن كنوع Notification)
        Notification smsNotification;
        
        // TODO: استدعاء Send() لكل منها وطباعة النتائج
        // سيتم استدعاء الدوال التي تم تجاوزها (overridden methods) بسبب تعدد الأشكال في وقت التشغيل (runtime polymorphism)
    }
}
quiz iconاختبر نفسك

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

جميع دروس Object Oriented Programming