Catégories
Programmation

Comprendre la différence entre new et override en C#

Je reviens parfois à la documentation de base Savoir quand utiliser les mots clés override et new quand j’ai un doute car cette subtilité du langage peut être source d’erreur très compliquée à débusquer.

Pour résumé avec deux phrases (prenez votre souffle) :

override est obligatoirement utilisé sur une méthode abstract et doit être utilisé (sinon warning du compilateur) sur une méthode virtual, il indique au compilateur d’utiliser la dernière méthode définie (pas de différence sur les types utilisés).

new peut être utilisé en redéfinition de méthode mais cette nouvelle méthode ne sera appelée que sur un appel direct à partir du type de la classe fille.

Vous préférez du code ? C’est parti :

using System;

namespace NewOrverride
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("--- ClasseBase ---");
            ClasseBase cb = new ClasseBase();
            cb.MethodeClassique();
            cb.MethodeVirtuelle();
            cb.MethodeAvecAppelInterne();

            Console.WriteLine("--- Classe avec override ---");
            ClasseAvecOverride caor = new ClasseAvecOverride();
            caor.MethodeClassique(); // override impossible donc appelle la méthode de la classe parent
            caor.MethodeVirtuelle();
            caor.MethodeAvecAppelInterne();

            Console.WriteLine("--- Classe avec override mais avec un type ClasseBase---");
            ClasseBase cbcaor = new ClasseAvecOverride();
            cbcaor.MethodeClassique();
            cbcaor.MethodeVirtuelle(); // override donc la méthode fille sera appelée
            cbcaor.MethodeAvecAppelInterne();

            Console.WriteLine("--- Classe sans new ---");
            ClasseSansNew csn = new ClasseSansNew();
            csn.MethodeClassique(); // Fonctionne mais avec un warning à la compilation
            csn.MethodeVirtuelle(); // Fonctionne mais avec un warning à la compilation
            csn.MethodeAvecAppelInterne();

            Console.WriteLine("--- Classe avec new ---");
            ClasseAvecNew can = new ClasseAvecNew();
            can.MethodeClassique(); // Même comportement mais plus de warning
            can.MethodeVirtuelle(); // Même comportement mais plus de warning
            can.MethodeAvecAppelInterne();

            Console.WriteLine("--- Classe avec new mais avec un type ClasseBase---");
            ClasseBase cbcan = new ClasseAvecNew();
            cbcan.MethodeClassique(); // Pas d'appel à la méthode de la classe fille !
            cbcan.MethodeVirtuelle(); // Pas d'appel à la méthode de la classe fille !
            cbcan.MethodeAvecAppelInterne();

            Console.WriteLine("--- Les appels surprises si vous n'avez pas remarqué---");
            cbcaor.MethodeAvecAppelInterne(); // ClasseAvecOverride dans un type ClasseBase
            cbcan.MethodeAvecAppelInterne(); // ClasseAvecNew dans un type ClasseBase
            can.MethodeAvecAppelInterne(); // ClasseAvecNew
            // Avec new vous ne pouvez accéder à la nouvelle méthode de la classe fille
            // UNIQUEMENT avec un accés direct à la méthode et par le type de la classe fille.
        }
    }

    public class ClasseBase
    {
        public void MethodeClassique()
        {
            Console.WriteLine("ClasseBase / MethodeClassique");
        }
        public virtual void MethodeVirtuelle()
        {
            Console.WriteLine("ClasseBase / MethodeVirtuelle");
        }
        // Méthode qui réserve des surprises...
        public void MethodeAvecAppelInterne()
        {
            MethodeVirtuelle();
        }
    }

    public class ClasseAvecOverride : ClasseBase
    {
        // Impossible car MethodeClassique n'est pas virtual
        //public override void MethodeClassique()
        //{
        //    Console.WriteLine("ClasseBase / MethodeClassique");
        //}     
        public override void MethodeVirtuelle()
        {
            Console.WriteLine("ClasseAvecOverride / MethodeVirtuelle");
        }
    }

    public class ClasseSansNew : ClasseBase
    {
        // Warning de masquage
        public void MethodeClassique()
        {
            Console.WriteLine("ClasseSansNew / MethodeClassique");
        }
        // Warning de choix de masquage
        public void MethodeVirtuelle()
        {
            Console.WriteLine("ClasseSansNew / MethodeVirtuelle");
        }
    }

    public class ClasseAvecNew : ClasseBase
    {
        public new void MethodeClassique()
        {
            Console.WriteLine("ClasseAvecNew / MethodeClassique");
        }
        public new void MethodeVirtuelle()
        {
            Console.WriteLine("ClasseAvecNew / MethodeVirtuelle");
        }
    }
}

Je dois quand même vous avouer que je n’ai jamais trouvé de cas d’illustration dans la vraie vie. Quelqu’un ?

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *