Versioning avec les mots clés override et new (Guide de programmation C#)
Le langage C# est conçu de telle sorte que le versioning entre les classes de base et les classes dérivées dans différentes bibliothèques puisse évoluer et préserver une compatibilité descendante. Cela signifie, par exemple, que l'introduction dans une classe de base d'un nouveau membre portant le même nom qu'un membre dans une classe dérivée est totalement prise en charge par C# et n'engendre pas de comportement imprévisible. Cela signifie également qu'une classe doit indiquer de façon explicite si une méthode est conçue pour substituer une méthode héritée ou s'il s'agit d'une nouvelle méthode qui masque simplement une méthode héritée portant un nom similaire.
C# permet aux classes dérivées de contenir des méthodes portant le même nom que des méthodes de classe de base.
-
La méthode de classe de base doit être définie comme virtuelle.
-
Si la méthode dans la classe dérivée n'est pas précédée des mots clés new ou override, le compilateur émet un avertissement et la méthode se comporte comme si le mot clé new était présent.
-
Si la méthode dans la classe dérivée est précédée du mot clé new, la méthode est définie comme étant indépendante de la méthode dans la classe de base.
-
Si la méthode dans la classe dérivée est précédée du mot clé override, les objets de la classe dérivée appelleront cette méthode plutôt que la méthode de la classe de base.
-
La méthode de la classe de base peut être appelée à partir de la classe dérivée à l'aide du mot clé base.
-
Les mots clés override, virtual et new peuvent également être appliqués aux propriétés, indexeurs et événements.
Par défaut, les méthodes C# ne sont pas virtuelles - si une méthode est déclarée comme virtuelle, toute classe qui hérite de la méthode peut en implémenter sa propre version. Pour créer une méthode virtuelle, le modificateur virtual est utilisé dans la déclaration de méthode de la classe de base. La classe dérivée peut ensuite substituer la méthode virtuelle de base avec le mot clé override ou masquer la méthode virtuelle dans la classe de base avec le mot clé new. Si ni le mot clé override ni le mot clé new ne sont spécifiés, le compilateur émettra un avertissement et la méthode dans la classe dérivée masquera la méthode dans la classe de base. Pour plus d'informations, consultez Avertissement du compilateur CS0108.
Pour démontrer ceci en pratique, supposez par exemple que la société A a créé une classe intitulée GraphicsClass, que votre programme utilise. GraphicsClass ressemble à ceci :
class GraphicsClass { public virtual void DrawLine() { } public virtual void DrawPoint() { } }
Votre société utilise cette classe, et vous l'utilisez pour dériver votre propre classe, en ajoutant une nouvelle méthode :
Votre application est utilisée sans problème, jusqu'à ce que la société A sorte une nouvelle version de GraphicsClass, qui ressemble à ceci :
class GraphicsClass { public virtual void DrawLine() { } public virtual void DrawPoint() { } public virtual void DrawRectangle() { } }
La nouvelle version de GraphicsClass contient désormais une méthode intitulée DrawRectangle. Au début, rien ne se produit. La nouvelle version est encore binairement compatible avec l'ancienne - tous les logiciels que vous avez déployés continueront à fonctionner, même si la nouvelle classe est installée sur ces systèmes informatiques. Tout appel existant à la méthode DrawRectangle continuera à faire référence à votre version, dans votre classe dérivée.
Toutefois, une fois que vous aurez recompilé votre application à l'aide de la nouvelle version de GraphicsClass, vous recevrez un avertissement du compilateur. Pour plus d'informations, consultez Avertissement du compilateur CS0108.
Cet avertissement vous informe que vous devez envisager comment vous souhaitez que votre méthode DrawRectangle se comporte dans votre application.
Si vous souhaitez que votre méthode substitue la nouvelle méthode de la classe de base, utilisez le mot clé override, comme ceci :
class YourDerivedGraphicsClass : GraphicsClass { public override void DrawRectangle() { } }
Le mot clé override garantit que tous les objets dérivés de YourDerivedGraphicsClass utiliseront la version de classe dérivée de DrawRectangle. Les objets dérivés de YourDerivedGraphicsClass peuvent accéder encore à la version de la classe de base de DrawRectangle à l'aide du mot clé base, comme ceci :
Si vous ne souhaitez pas que votre méthode substitue la nouvelle méthode de classe de base, tenez compte des considérations suivantes. Pour éviter toute confusion entre les deux méthodes, vous pouvez renommer votre méthode. Cela peut prendre du temps, engendrer des erreurs et simplement pas pratique dans certaines situations. Toutefois, si votre projet est relativement petit, vous pouvez utiliser les options de refactorisation de Visual Studio pour renommer la méthode. Pour plus d'informations, consultez Types et classes de refactorisation.
Par ailleurs, vous pouvez empêcher l'avertissement à l'aide du mot clé new dans votre définition de classe dérivée, comme ceci :
L'utilisation du mot clé new indique au compilateur que votre définition masque la définition contenue dans la classe de base. Il s'agit du comportement par défaut.
Substitution et sélection de méthode
Lorsqu'une méthode est nommée sur une classe, le compilateur C# sélectionne la meilleure méthode à appeler si plusieurs méthodes sont compatibles avec l'appel, comme lorsque deux méthodes portent le même nom, et les paramètres qui sont compatibles avec le paramètre transmis. Les méthodes suivantes seraient compatibles :
public class Derived : Base { public override void DoWork(int param) { } public void DoWork(double param) { } }
Lorsque DoWork est appelée sur une instance de Derived, le compilateur C# essaiera d'abord de rendre l'appel compatible avec les versions de DoWork déclarées à l'origine sur Derived. Les méthodes override ne sont pas considérées comme déclarées sur une classe, il s'agit de nouvelles implémentations d'une méthode déclarées sur une classe de base. Le compilateur C# essaiera de faire correspondre l'appel avec une méthode substituée portant le même nom et doté de paramètres compatibles uniquement s'il ne parvient pas à faire correspondre l'appel de méthode et la méthode d'origine sur Derived. Par exemple :
Étant donné que la variable val peut être convertie implicitement en un double, le compilateur C# appelle DoWork(double) au lieu de DoWork(int). Il y a deux manières d'éviter ceci. Premièrement, évitez de déclarer de nouvelles méthodes portant le même nom que des méthodes virtuelles. Deuxièmement, vous pouvez indiquer au compilateur C# d'appeler la méthode virtuelle en le faisant chercher dans la liste de méthodes de la classe de base par casting d'une instance de Derived en Base. Étant donné que la méthode est virtuelle, l'implémentation de DoWork(int) sur Derived sera appelée. Par exemple :