Partager via


Savoir quand utiliser le remplacement et les nouveaux mots clés (Guide de programmation C#)

En C#, une méthode dans une classe dérivée peut avoir le même nom qu’une méthode dans la classe de base. Vous pouvez spécifier comment les méthodes interagissent en utilisant les mots-clés new et override. Le override modificateur étend la méthode de classe virtual de base et le new modificateur masque une méthode de classe de base accessible. La différence est illustrée dans les exemples de cette rubrique.

Dans une application console, déclarez les deux classes suivantes et BaseClassDerivedClass. DerivedClass hérite de BaseClass.

class BaseClass  
{  
    public void Method1()  
    {  
        Console.WriteLine("Base - Method1");  
    }  
}  
  
class DerivedClass : BaseClass  
{  
    public void Method2()  
    {  
        Console.WriteLine("Derived - Method2");  
    }  
}  

Dans la Main méthode, déclarez des variables bc, dcet bcdc.

  • bc est de type BaseClass, et sa valeur est de type BaseClass.

  • dc est de type DerivedClass, et sa valeur est de type DerivedClass.

  • bcdc est de type BaseClass, et sa valeur est de type DerivedClass. Il s’agit de la variable à prendre en compte.

Comme bc et bcdc ont le type BaseClass, ils ne peuvent accéder directement qu’à Method1, sauf si vous effectuez un cast. La variable dc peut accéder aux deux Method1 et Method2. Ces relations sont indiquées dans le code suivant.

class Program  
{  
    static void Main(string[] args)  
    {  
        BaseClass bc = new BaseClass();  
        DerivedClass dc = new DerivedClass();  
        BaseClass bcdc = new DerivedClass();  
  
        bc.Method1();  
        dc.Method1();  
        dc.Method2();  
        bcdc.Method1();  
    }  
    // Output:  
    // Base - Method1  
    // Base - Method1  
    // Derived - Method2  
    // Base - Method1  
}  

Ensuite, ajoutez la méthode suivante Method2 à BaseClass. La signature de cette méthode correspond à la signature de la Method2 méthode dans DerivedClass.

public void Method2()  
{  
    Console.WriteLine("Base - Method2");  
}  

Étant donné que BaseClass maintenant a une Method2 méthode, une deuxième instruction appelante peut être ajoutée pour BaseClass les variables bc et bcdc, comme illustré dans le code suivant.

bc.Method1();  
bc.Method2();  
dc.Method1();  
dc.Method2();  
bcdc.Method1();  
bcdc.Method2();  

Lorsque vous générez le projet, vous voyez que l’ajout de la méthode Method2 dans BaseClass provoque un avertissement. L’avertissement indique que la Method2 méthode dans DerivedClass masque la Method2 méthode dans BaseClass. Vous êtes invité à utiliser le new mot clé dans la Method2 définition si vous avez l’intention de provoquer ce résultat. Vous pouvez également renommer l’une des Method2 méthodes pour résoudre l’avertissement, mais ce n’est pas toujours pratique.

Avant d’ajouter new, exécutez le programme pour voir la sortie produite par les instructions d’appel supplémentaires. Les résultats suivants sont affichés.

// Output:  
// Base - Method1  
// Base - Method2  
// Base - Method1  
// Derived - Method2  
// Base - Method1  
// Base - Method2  

Le new mot-clé conserve les relations qui produisent ce résultat, mais supprime l’avertissement. Les variables de type BaseClass continuent d’accéder aux membres de BaseClass, et la variable de type DerivedClass continue d’accéder aux membres de DerivedClass en premier, et ensuite considère les membres hérités de BaseClass.

Pour supprimer l’avertissement, ajoutez le modificateur new à la définition de Method2 dans DerivedClass, comme indiqué dans le code suivant. Le modificateur peut être ajouté avant ou après public.

public new void Method2()  
{  
    Console.WriteLine("Derived - Method2");  
}  

Réexécutez le programme pour vérifier que la sortie n’a pas changé. Vérifiez également que l’avertissement n’apparaît plus. En utilisant new, vous affirmez que vous savez que le membre qu’il modifie masque un membre hérité de la classe de base. Pour plus d’informations sur le masquage de nom par héritage, consultez new, modificateur.

Pour comparer ce comportement aux effets de l’utilisation override, ajoutez la méthode suivante à DerivedClass. Le override modificateur peut être ajouté avant ou après public.

public override void Method1()  
{  
    Console.WriteLine("Derived - Method1");  
}  

Ajoutez le modificateur virtual à la définition de Method1 dans BaseClass. Le virtual modificateur peut être ajouté avant ou après public.

public virtual void Method1()  
{  
    Console.WriteLine("Base - Method1");  
}  

Réexécutez le projet. Notez en particulier les deux dernières lignes de la sortie suivante.

// Output:  
// Base - Method1  
// Base - Method2  
// Derived - Method1  
// Derived - Method2  
// Derived - Method1  
// Base - Method2  

L’utilisation du override modificateur permet bcdc d’accéder à la Method1 méthode définie dans DerivedClass. En règle générale, il s’agit du comportement souhaité dans les hiérarchies d’héritage. Vous souhaitez que les objets qui ont des valeurs créées à partir de la classe dérivée utilisent les méthodes définies dans la classe dérivée. Vous obtenez ce comportement en utilisant override pour étendre la méthode de classe de base.

Le code suivant contient l’exemple complet.

using System;  
using System.Text;  
  
namespace OverrideAndNew  
{  
    class Program  
    {  
        static void Main(string[] args)  
        {  
            BaseClass bc = new BaseClass();  
            DerivedClass dc = new DerivedClass();  
            BaseClass bcdc = new DerivedClass();  
  
            // The following two calls do what you would expect. They call  
            // the methods that are defined in BaseClass.  
            bc.Method1();  
            bc.Method2();  
            // Output:  
            // Base - Method1  
            // Base - Method2  
  
            // The following two calls do what you would expect. They call  
            // the methods that are defined in DerivedClass.  
            dc.Method1();  
            dc.Method2();  
            // Output:  
            // Derived - Method1  
            // Derived - Method2  
  
            // The following two calls produce different results, depending
            // on whether override (Method1) or new (Method2) is used.  
            bcdc.Method1();  
            bcdc.Method2();  
            // Output:  
            // Derived - Method1  
            // Base - Method2  
        }  
    }  
  
    class BaseClass  
    {  
        public virtual void Method1()  
        {  
            Console.WriteLine("Base - Method1");  
        }  
  
        public virtual void Method2()  
        {  
            Console.WriteLine("Base - Method2");  
        }  
    }  
  
    class DerivedClass : BaseClass  
    {  
        public override void Method1()  
        {  
            Console.WriteLine("Derived - Method1");  
        }  
  
        public new void Method2()  
        {  
            Console.WriteLine("Derived - Method2");  
        }  
    }  
}  

L’exemple suivant illustre un comportement similaire dans un contexte différent. L’exemple définit trois classes : une classe de base nommée Car et deux classes dérivées de celle-ci, ConvertibleCar et Minivan. La classe de base contient une DescribeCar méthode. La méthode affiche une description de base d’une voiture, puis appelle ShowDetails pour fournir des informations supplémentaires. Chacune des trois classes définit une ShowDetails méthode. Le new modificateur est utilisé pour définir ShowDetails dans la ConvertibleCar classe. Le override modificateur est utilisé pour définir ShowDetails dans la Minivan classe.

// Define the base class, Car. The class defines two methods,  
// DescribeCar and ShowDetails. DescribeCar calls ShowDetails, and each derived  
// class also defines a ShowDetails method. The example tests which version of  
// ShowDetails is selected, the base class method or the derived class method.  
class Car  
{  
    public void DescribeCar()  
    {  
        System.Console.WriteLine("Four wheels and an engine.");  
        ShowDetails();  
    }  
  
    public virtual void ShowDetails()  
    {  
        System.Console.WriteLine("Standard transportation.");  
    }  
}  
  
// Define the derived classes.  
  
// Class ConvertibleCar uses the new modifier to acknowledge that ShowDetails  
// hides the base class method.  
class ConvertibleCar : Car  
{  
    public new void ShowDetails()  
    {  
        System.Console.WriteLine("A roof that opens up.");  
    }  
}  
  
// Class Minivan uses the override modifier to specify that ShowDetails  
// extends the base class method.  
class Minivan : Car  
{  
    public override void ShowDetails()  
    {  
        System.Console.WriteLine("Carries seven people.");  
    }  
}  

L'exemple teste quelle version de ShowDetails est appelée. La méthode suivante, TestCars1 déclare une instance de chaque classe, puis appelle DescribeCar sur chaque instance.

public static void TestCars1()  
{  
    System.Console.WriteLine("\nTestCars1");  
    System.Console.WriteLine("----------");  
  
    Car car1 = new Car();  
    car1.DescribeCar();  
    System.Console.WriteLine("----------");  
  
    // Notice the output from this test case. The new modifier is  
    // used in the definition of ShowDetails in the ConvertibleCar  
    // class.
  
    ConvertibleCar car2 = new ConvertibleCar();  
    car2.DescribeCar();  
    System.Console.WriteLine("----------");  
  
    Minivan car3 = new Minivan();  
    car3.DescribeCar();  
    System.Console.WriteLine("----------");  
}  

TestCars1 produit la sortie suivante. Notez en particulier les résultats pour car2, qui ne sont probablement pas ce que vous attendiez. Le type de l’objet est ConvertibleCar, mais DescribeCar n’accède pas à la version de ShowDetails celle-ci définie dans la ConvertibleCar classe, car cette méthode est déclarée avec le new modificateur, et non le override modificateur. Par conséquent, un ConvertibleCar objet affiche la même description qu’un Car objet. Contrastez les résultats pour car3, qui est un Minivan objet. Dans ce cas, la ShowDetails méthode déclarée dans la Minivan classe remplace la ShowDetails méthode déclarée dans la Car classe et la description affichée décrit un minivan.

// TestCars1  
// ----------  
// Four wheels and an engine.  
// Standard transportation.  
// ----------  
// Four wheels and an engine.  
// Standard transportation.  
// ----------  
// Four wheels and an engine.  
// Carries seven people.  
// ----------  

TestCars2 crée une liste d’objets qui ont le type Car. Les valeurs des objets sont instanciées à partir des classes Car, ConvertibleCar, et Minivan. DescribeCar est appelé sur chaque élément de la liste. Le code suivant montre la définition de TestCars2.

public static void TestCars2()  
{  
    System.Console.WriteLine("\nTestCars2");  
    System.Console.WriteLine("----------");  
  
    var cars = new List<Car> { new Car(), new ConvertibleCar(),
        new Minivan() };  
  
    foreach (var car in cars)  
    {  
        car.DescribeCar();  
        System.Console.WriteLine("----------");  
    }  
}  

La sortie suivante s’affiche. Notez qu’il est identique à la sortie affichée par TestCars1. La ShowDetails méthode de la ConvertibleCar classe n’est pas appelée, que le type de l’objet soit ConvertibleCar, comme dans TestCars1, ou Car, comme dans TestCars2. car3 À l'inverse, dans les deux cas, appelle la méthode ShowDetails de la classe Minivan, qu'elle soit de type Minivan ou de type Car.

// TestCars2  
// ----------  
// Four wheels and an engine.  
// Standard transportation.  
// ----------  
// Four wheels and an engine.  
// Standard transportation.  
// ----------  
// Four wheels and an engine.  
// Carries seven people.  
// ----------  

Méthodes TestCars3 et TestCars4 complètent l'exemple. Ces méthodes appellent ShowDetails directement, d’abord à partir d’objets déclarés pour avoir le type ConvertibleCar et Minivan (TestCars3), puis à partir d’objets déclarés pour avoir le type Car (TestCars4). Le code suivant définit ces deux méthodes.

public static void TestCars3()  
{  
    System.Console.WriteLine("\nTestCars3");  
    System.Console.WriteLine("----------");  
    ConvertibleCar car2 = new ConvertibleCar();  
    Minivan car3 = new Minivan();  
    car2.ShowDetails();  
    car3.ShowDetails();  
}  
  
public static void TestCars4()  
{  
    System.Console.WriteLine("\nTestCars4");  
    System.Console.WriteLine("----------");  
    Car car2 = new ConvertibleCar();  
    Car car3 = new Minivan();  
    car2.ShowDetails();  
    car3.ShowDetails();  
}  

Les méthodes produisent la sortie suivante, qui correspond aux résultats du premier exemple de cette rubrique.

// TestCars3  
// ----------  
// A roof that opens up.  
// Carries seven people.  
  
// TestCars4  
// ----------  
// Standard transportation.  
// Carries seven people.  

Le code suivant montre le projet complet et sa sortie.

using System;  
using System.Collections.Generic;  
using System.Linq;  
using System.Text;  
  
namespace OverrideAndNew2  
{  
    class Program  
    {  
        static void Main(string[] args)  
        {  
            // Declare objects of the derived classes and test which version  
            // of ShowDetails is run, base or derived.  
            TestCars1();  
  
            // Declare objects of the base class, instantiated with the  
            // derived classes, and repeat the tests.  
            TestCars2();  
  
            // Declare objects of the derived classes and call ShowDetails  
            // directly.  
            TestCars3();  
  
            // Declare objects of the base class, instantiated with the  
            // derived classes, and repeat the tests.  
            TestCars4();  
        }  
  
        public static void TestCars1()  
        {  
            System.Console.WriteLine("\nTestCars1");  
            System.Console.WriteLine("----------");  
  
            Car car1 = new Car();  
            car1.DescribeCar();  
            System.Console.WriteLine("----------");  
  
            // Notice the output from this test case. The new modifier is  
            // used in the definition of ShowDetails in the ConvertibleCar  
            // class.
            ConvertibleCar car2 = new ConvertibleCar();  
            car2.DescribeCar();  
            System.Console.WriteLine("----------");  
  
            Minivan car3 = new Minivan();  
            car3.DescribeCar();  
            System.Console.WriteLine("----------");  
        }  
        // Output:  
        // TestCars1  
        // ----------  
        // Four wheels and an engine.  
        // Standard transportation.  
        // ----------  
        // Four wheels and an engine.  
        // Standard transportation.  
        // ----------  
        // Four wheels and an engine.  
        // Carries seven people.  
        // ----------  
  
        public static void TestCars2()  
        {  
            System.Console.WriteLine("\nTestCars2");  
            System.Console.WriteLine("----------");  
  
            var cars = new List<Car> { new Car(), new ConvertibleCar(),
                new Minivan() };  
  
            foreach (var car in cars)  
            {  
                car.DescribeCar();  
                System.Console.WriteLine("----------");  
            }  
        }  
        // Output:  
        // TestCars2  
        // ----------  
        // Four wheels and an engine.  
        // Standard transportation.  
        // ----------  
        // Four wheels and an engine.  
        // Standard transportation.  
        // ----------  
        // Four wheels and an engine.  
        // Carries seven people.  
        // ----------  
  
        public static void TestCars3()  
        {  
            System.Console.WriteLine("\nTestCars3");  
            System.Console.WriteLine("----------");  
            ConvertibleCar car2 = new ConvertibleCar();  
            Minivan car3 = new Minivan();  
            car2.ShowDetails();  
            car3.ShowDetails();  
        }  
        // Output:  
        // TestCars3  
        // ----------  
        // A roof that opens up.  
        // Carries seven people.  
  
        public static void TestCars4()  
        {  
            System.Console.WriteLine("\nTestCars4");  
            System.Console.WriteLine("----------");  
            Car car2 = new ConvertibleCar();  
            Car car3 = new Minivan();  
            car2.ShowDetails();  
            car3.ShowDetails();  
        }  
        // Output:  
        // TestCars4  
        // ----------  
        // Standard transportation.  
        // Carries seven people.  
    }  
  
    // Define the base class, Car. The class defines two virtual methods,  
    // DescribeCar and ShowDetails. DescribeCar calls ShowDetails, and each derived  
    // class also defines a ShowDetails method. The example tests which version of  
    // ShowDetails is used, the base class method or the derived class method.  
    class Car  
    {  
        public virtual void DescribeCar()  
        {  
            System.Console.WriteLine("Four wheels and an engine.");  
            ShowDetails();  
        }  
  
        public virtual void ShowDetails()  
        {  
            System.Console.WriteLine("Standard transportation.");  
        }  
    }  
  
    // Define the derived classes.  
  
    // Class ConvertibleCar uses the new modifier to acknowledge that ShowDetails  
    // hides the base class method.  
    class ConvertibleCar : Car  
    {  
        public new void ShowDetails()  
        {  
            System.Console.WriteLine("A roof that opens up.");  
        }  
    }  
  
    // Class Minivan uses the override modifier to specify that ShowDetails  
    // extends the base class method.  
    class Minivan : Car  
    {  
        public override void ShowDetails()  
        {  
            System.Console.WriteLine("Carries seven people.");  
        }  
    }  
  
}  

Voir aussi