Parole chiave virtual e override
Fa parte della sezione Programmazione orientata agli oggetti del percorso C# di Coddy. Lezione 21 di 70.
Quando una classe derivata eredita un metodo, a volte vuoi cambiare completamente il comportamento di quel metodo. Le parole chiave virtual e override collaborano per renderlo possibile in modo controllato.
Contrassegna un metodo come virtual nella classe base per indicare che le classi derivate possono sostituirne l’implementazione:
public class Animal
{
public virtual void Speak()
{
Console.WriteLine("Some sound");
}
}
public class Dog : Animal
{
public override void Speak()
{
Console.WriteLine("Woof!");
}
}La parola chiave override nella classe derivata indica al compilatore che stai sostituendo intenzionalmente il metodo della classe base. Senza virtual sul metodo della classe base, non puoi usare override.
La vera potenza si vede quando usi un riferimento alla classe base per contenere un oggetto derivato:
Animal myPet = new Dog();
myPet.Speak(); // Output: Woof!Anche se myPet è dichiarato come Animal, C# chiama la versione di Dog di Speak(). Questo si chiama polimorfismo in fase di esecuzione: il metodo effettivamente chiamato dipende dal tipo reale dell'oggetto, non dal tipo dichiarato della variabile.
Puoi comunque accedere all’implementazione di base usando base.Speak() all’interno del tuo override se vuoi estendere il comportamento anziché sostituirlo completamente.
Sfida
FacileCostruiamo un sistema di notifiche che dimostri come le classi derivate possano eseguire l'override completo del comportamento della classe base usando le parole chiave virtual e override, mostrando al contempo la potenza del polimorfismo in fase di esecuzione.
Creerai tre file per organizzare il codice:
Notification.cs: definisci una classeNotificationnello spazio dei nomiAlerts. Questa classe base rappresenta una notifica generica con una proprietàMessage(string) e un costruttore che la imposta. Includi un metodovirtualchiamatoSend()che restituisce"Sending notification: {Message}".EmailNotification.cs: definisci una classeEmailNotificationnello spazio dei nomiAlertsche eredita daNotification. Aggiungi una proprietàRecipient(string) e un costruttore che accetta sia il messaggio sia il destinatario (usabaseper passare il messaggio). Esegui l'override del metodoSend()affinché restituisca"Emailing {Recipient}: {Message}".SmsNotification.cs: definisci una classeSmsNotificationnello spazio dei nomiAlertsche eredita anch'essa daNotification. Aggiungi una proprietàPhoneNumber(string) e un costruttore che accetta sia il messaggio sia il numero di telefono. Esegui l'override diSend()affinché restituisca"SMS to {PhoneNumber}: {Message}".Program.cs: nel file principale, crea istanze di tutti e tre i tipi di notifica usando i valori di input. Poi dimostra il polimorfismo in fase di esecuzione memorizzando tutte e tre in variabili di tipoNotificatione chiamandoSend()su ciascuna.
Riceverai quattro input:
- Il messaggio di notifica
- L'indirizzo email del destinatario
- Il numero di telefono per gli SMS
Stampa il risultato della chiamata a Send() su ciascuna notifica, memorizzata come riferimento alla classe base:
{base notification Send() result}
{email notification Send() result}
{sms notification Send() result}Ad esempio, se gli input sono Meeting at 3pm, alice@email.com e 555-1234, l'output dovrebbe essere:
Sending notification: Meeting at 3pm
Emailing alice@email.com: Meeting at 3pm
SMS to 555-1234: Meeting at 3pmNota che, anche se tutte e tre sono memorizzate in variabili di tipo Notification, ognuna chiama la propria versione di Send() sottoposta a override. Questo è il polimorfismo in fase di esecuzione!
Provalo tu
using System;
using Alerts;
class Program
{
public static void Main(string[] args)
{
// Leggi gli input
string message = Console.ReadLine();
string email = Console.ReadLine();
string phone = Console.ReadLine();
// TODO: Crea istanze di tutti e tre i tipi di notifica
// Memorizzale in variabili di tipo Notification per dimostrare il polimorfismo
// TODO: Crea un'istanza della classe base Notification
Notification baseNotification;
// TODO: Crea un'istanza di EmailNotification (memorizzata come tipo Notification)
Notification emailNotification;
// TODO: Crea un'istanza di SmsNotification (memorizzata come tipo Notification)
Notification smsNotification;
// TODO: Chiama Send() su ciascuna istanza e stampa i risultati
// I metodi ridefiniti verranno chiamati grazie al polimorfismo a runtime
}
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Fondamenti della programmazione orientata agli oggetti
File esterniNamespace e direttiveIntroduzione a classi e oggettiLa parola chiave "this"Metodi e parametriCampi e proprietàCostruttoriInizializzatori di oggettiRiepilogo - Calcolatrice semplice4Ereditarietà
Sintassi di base dell'ereditarietà (:)La parola chiave 'base'Parole chiave virtual e overrideClassi sealedLa classe base 'object'Riepilogo - Gerarchia dei dipendenti7Funzionalità avanzate
Sovraccarico degli operatoriIndicizzatori (this[])Override di ToString()Metodi di estensioneRiepilogo - Lista personalizzata10Pattern di progettazione Parte 1
Introduzione ai pattern di progettazioneSingleton thread-safePattern FactoryPattern Observer (eventi)Pattern Strategy2Proprietà e membri statici
Proprietà implementate automaticamenteProprietà di sola lettura e di sola scritturaCampi e metodi staticiClassi staticheMembri con corpo di espressione5Polimorfismo e interfacce
Polimorfismo a compile time e runtimeInterfaccia o classe astrattaInterfacce multipleInterfacce espliciteUpcasting e downcastingRipasso: calcolatore di forme8Concetti avanzati di programmazione a oggetti
Composizione invece dell'ereditarietàTipi generici (classi e metodi)Delegati ed eventiAttributi e reflectionIDisposable e istruzione usingNozioni di base sull'iniezione delle dipendenze11Pattern di progettazione, parte 2
Pattern del ComandoPattern dell’AdattatorePattern del DecoratorePattern Template MethodPattern dello StatoPattern Composito3Architettura delle classi
Dati di istanza vs staticiParole chiave 'readonly' e 'const'Campi di supportoRiepilogo - Gestore di conti bancari6Incapsulamento
Modificatori di accessoProprietà per l'incapsulamentoImplementazione dell'occultamento dei datiModelli di immutabilitàRiepilogo - Registri degli studentiEsercitati da solo: Compilatore C# online