Héritage dans C# et .NETInheritance in C# and .NET

Ce didacticiel vous présente l’héritage dans C#.This tutorial introduces you to inheritance in C#. L’héritage est une fonctionnalité des langages de programmation orientés objet qui vous permet de définir une classe de base qui fournit des fonctionnalités spécifiques (données et comportement) et de définir des classes dérivées qui héritent ou substituent cette fonctionnalité.Inheritance is a feature of object-oriented programming languages that allows you to define a base class that provides specific functionality (data and behavior) and to define derived classes that either inherit or override that functionality.

Configuration requisePrerequisites

Ce didacticiel part du principe que vous avez installé le kit SDK .NET Core.This tutorial assumes that you've installed the .NET Core SDK. Visitez la page des téléchargements .net Core pour le télécharger.Visit the .NET Core Downloads page to download it. Il vous faut également un éditeur de code.You also need a code editor. Ce didacticiel utilise Visual Studio Code, mais vous pouvez utiliser l’éditeur de code de votre choix.This tutorial uses Visual Studio Code, although you can use any code editor of your choice.

Exécution des exemplesRunning the examples

Pour créer et exécuter les exemples de ce didacticiel, vous utilisez l’utilitaire dotnet en ligne de commande.To create and run the examples in this tutorial, you use the dotnet utility from the command line. Pour chaque exemple, procédez comme suit :Follow these steps for each example:

  1. Créez un répertoire pour stocker l’exemple.Create a directory to store the example.
  2. Entrez la commande dotnet new console dans l’invite de commandes pour créer un projet .NET Core.Enter the dotnet new console command at a command prompt to create a new .NET Core project.
  3. Copiez et collez le code de l’exemple dans votre éditeur de code.Copy and paste the code from the example into your code editor.
  4. Entrez la commande dotnet restore à partir de la ligne de commande pour charger ou restaurer les dépendances du projet.Enter the dotnet restore command from the command line to load or restore the project's dependencies.

Notes

À partir du kit SDK .NET Core 2.0, vous n’avez pas à exécuter dotnet restore, car il est exécuté implicitement par toutes les commandes qui réclament une restauration, comme dotnet new, dotnet build et dotnet run.Starting with .NET Core 2.0 SDK, you don't have to run dotnet restore because it's run implicitly by all commands that require a restore to occur, such as dotnet new, dotnet build and dotnet run. Cette commande reste néanmoins valide dans certains scénarios où une restauration explicite est nécessaire, comme des builds d’intégration continue dans Azure DevOps Services ou dans les systèmes de génération qui doivent contrôler explicitement le moment auquel la restauration se produit.It's still a valid command in certain scenarios where doing an explicit restore makes sense, such as continuous integration builds in Azure DevOps Services or in build systems that need to explicitly control the time at which the restore occurs.

  1. Entrez la commande dotnet run pour compiler et exécuter l’exemple.Enter the dotnet run command to compile and execute the example.

Présentation : Qu’est-ce que l’héritage ?Background: What is inheritance?

L’héritage est un des attributs fondamentaux de la programmation orientée objet.Inheritance is one of the fundamental attributes of object-oriented programming. Il vous permet de définir une classe enfant qui réutilise (hérite), étend ou modifie le comportement d’une classe parente.It allows you to define a child class that reuses (inherits), extends, or modifies the behavior of a parent class. La classe dont les membres sont hérités s’appelle la classe de base.The class whose members are inherited is called the base class. La classe qui hérite des membres de la classe de base est appelée la classe dérivée.The class that inherits the members of the base class is called the derived class.

C# et .NET prennent uniquement en charge l’héritage simple.C# and .NET support single inheritance only. C’est-à-dire qu’une classe ne peut hériter que d'une seule classe.That is, a class can only inherit from a single class. Toutefois, l’héritage est transitif, ce qui permet de définir une hiérarchie d’héritage pour un ensemble de types.However, inheritance is transitive, which allows you to define an inheritance hierarchy for a set of types. En d’autres termes, le type D peut hériter du type C, qui hérite du type B, qui hérite du type de classe de base A.In other words, type D can inherit from type C, which inherits from type B, which inherits from the base class type A. Étant donné que l’héritage est transitif, les membres de type A sont disponibles pour le type D.Because inheritance is transitive, the members of type A are available to type D.

Tous les membres d’une classe de base ne sont pas hérités par les classes dérivées.Not all members of a base class are inherited by derived classes. Les membres suivants ne sont pas hérités :The following members are not inherited:

  • Les constructeurs statiques, qui initialisent les données statiques d’une classe.Static constructors, which initialize the static data of a class.

  • Les Constructeurs d’instance, que vous appelez pour créer une nouvelle instance de la classe.Instance constructors, which you call to create a new instance of the class. Chaque classe doit définir ses propres constructeurs.Each class must define its own constructors.

  • Les finaliseurs, qui sont appelés par le récupérateur de mémoire du runtime pour détruire les instances d’une classe.Finalizers, which are called by the runtime's garbage collector to destroy instances of a class.

Bien que tous les autres membres de classe de base sont hérités par les classes dérivées, leur visibilité dépend de leur accessibilité.While all other members of a base class are inherited by derived classes, whether they are visible or not depends on their accessibility. L’accessibilité d’un membre affecte sa visibilité pour les classes dérivées de la manière suivante :A member's accessibility affects its visibility for derived classes as follows:

  • Les membres Privés sont visibles uniquement dans les classes dérivées qui sont imbriquées dans leur classe de base.Private members are visible only in derived classes that are nested in their base class. Sinon, ils ne sont pas visibles dans les classes dérivées.Otherwise, they are not visible in derived classes. Dans l’exemple suivant, A.B est une classe imbriquée qui dérive de A, et C dérive de A.In the following example, A.B is a nested class that derives from A, and C derives from A. Le champ privé A.value est visible dans A.B.The private A.value field is visible in A.B. Toutefois, si vous supprimez les commentaires de la méthode C.GetValue et essayez de compiler l’exemple, il génère l’erreur de compilateur CS0122 : « 'A.value est inaccessible en raison de son niveau de protection ».However, if you remove the comments from the C.GetValue method and attempt to compile the example, it produces compiler error CS0122: "'A.value' is inaccessible due to its protection level."

    using System;
    
    public class A 
    {
       private int value = 10;
    
       public class B : A
       {
           public int GetValue()
           {
               return this.value;
           }     
       }
    }
    
    public class C : A
    {
    //    public int GetValue()
    //    {
    //        return this.value;
    //    }
    }
    
    public class Example
    {
        public static void Main(string[] args)
        {
            var b = new A.B();
            Console.WriteLine(b.GetValue());
        }
    }
    // The example displays the following output:
    //       10
    
  • Les membres protégés sont visibles uniquement dans les classes dérivées.Protected members are visible only in derived classes.

  • Les membres internes sont visibles uniquement dans les classes dérivées qui sont trouvent dans le même assembly que la classe de base.Internal members are visible only in derived classes that are located in the same assembly as the base class. Ils ne sont pas visibles dans les classes dérivées situées dans un autre assembly à partir de la classe de base.They are not visible in derived classes located in a different assembly from the base class.

  • Les membres publics sont visibles dans les classes dérivées et font partie de l’interface publique de la classe dérivée.Public members are visible in derived classes and are part of the derived class' public interface. Les membres publics hérités peuvent être appelés comme s’ils étaient définis dans la classe dérivée.Public inherited members can be called just as if they are defined in the derived class. Dans l’exemple suivant, la classe A définit une méthode nommée Method1, et la classe B hérite de la classe A.In the following example, class A defines a method named Method1, and class B inherits from class A. L’exemple appelle ensuite Method1 comme s’il s’agissait d’une méthode d’instance sur B.The example then calls Method1 as if it were an instance method on B.

public class A
{
    public void Method1()
    {
        // Method implementation.
    }
}

public class B : A
{ }

public class Example
{
    public static void Main()
    {
        B b = new B();
        b.Method1();
    }
}

Les classes dérivées peuvent également substituer les membres hérités en fournissant une implémentation alternative.Derived classes can also override inherited members by providing an alternate implementation. Pour être en mesure de substituer un membre, le membre de la classe de base doit être marqué avec le mot-clé virtual.In order to be able to override a member, the member in the base class must be marked with the virtual keyword. Par défaut, les membres de classe de base ne sont pas marqués comme virtual et ne peut pas être substitués.By default, base class members are not marked as virtual and cannot be overridden. Une tentative de substituer un membre non virtuel, comme dans l’exemple suivant, génère l’erreur de compilateur CS0506 : « <member> : impossible de substituer le membre hérité <member>, car il n’est pas marqué comme virtual, abstract ou override.Attempting to override a non-virtual member, as the following example does, generates compiler error CS0506: "<member> cannot override inherited member <member> because it is not marked virtual, abstract, or override.

public class A
{
    public void Method1()
    {
        // Do something.
    }
}

public class B : A
{
    public override void Method1() // Generates CS0506.
    {
        // Do something else.
    }
}

Dans certains cas, une classe dérivée doit remplacer l’implémentation de la classe de base.In some cases, a derived class must override the base class implementation. Les membres de classe de base marqués avec le mot-clé abstract requièrent que les classes dérivées les remplacent.Base class members marked with the abstract keyword require that derived classes override them. Compiler l’exemple suivant génère l’erreur de compilateur CS0534, « <class> does not implement inherited abstract member <member> », car la classe B ne fournit aucune implémentation de A.Method1.Attempting to compile the following example generates compiler error CS0534, "<class> does not implement inherited abstract member <member>", because class B provides no implementation for A.Method1.

public abstract class A
{
    public abstract void Method1();
}

public class B : A // Generates CS0534.
{
    public void Method3()
    {
        // Do something.
    }
}

L’héritage s’applique uniquement aux classes et interfaces.Inheritance applies only to classes and interfaces. Les autres catégories de type (structures, délégués et énumérations) ne permettent pas l’héritage.Other type categories (structs, delegates, and enums) do not support inheritance. En raison de ces règles, la tentative de compilation de code comme l’exemple suivant génère l’erreur de compilateur CS0527 : « Le type 'ValueType' dans la liste des interfaces n’est pas une interface ».Because of these rules, attempting to compile code like the following example produces compiler error CS0527: "Type 'ValueType' in interface list is not an interface." Le message d’erreur indique que, même si vous pouvez définir les interfaces qu’implémente un struct, l’héritage n'est pas pris en charge.The error message indicates that, although you can define the interfaces that a struct implements, inheritance is not supported.

using System;

public struct ValueStructure : ValueType // Generates CS0527.
{
}

Héritage impliciteImplicit inheritance

Outre les types qui peuvent hériter via l’héritage simple, tous les types dans le système de types de .NET héritent implicitement de Object ou d’un type dérivé.Besides any types that they may inherit from through single inheritance, all types in the .NET type system implicitly inherit from Object or a type derived from it. Les fonctionnalités communes de Object sont disponibles pour n’importe quel type.The common functionality of Object is available to any type.

Pour comprendre ce que l’héritage implicite signifie, nous allons définir une nouvelle classe, SimpleClass, qui est simplement une définition de classe vide :To see what implicit inheritance means, let's define a new class, SimpleClass, that is simply an empty class definition:

public class SimpleClass
{ }

Vous pouvez ensuite utiliser la réflexion (qui permet d’inspecter les métadonnées d’un type pour obtenir des informations sur ce type) pour obtenir la liste des membres qui appartiennent au type SimpleClass.You can then use reflection (which lets you inspect a type's metadata to get information about that type) to get a list of the members that belong to the SimpleClass type. Même si vous n’avez pas défini de membres dans votre classe SimpleClass, la sortie de l’exemple indique qu’il a en fait neuf membres.Although you haven't defined any members in your SimpleClass class, output from the example indicates that it actually has nine members. Un de ces membres est un constructeur sans paramètre (ou par défaut) qui est fourni automatiquement pour le type SimpleClass par le compilateur C#.One of these members is a parameterless (or default) constructor that is automatically supplied for the SimpleClass type by the C# compiler. Les huit restants sont membres de Object, le type à partir duquel toutes les classes et interfaces du système de type .NET héritent implicitement.The remaining eight are members of Object, the type from which all classes and interfaces in the .NET type system ultimately implicitly inherit.

using System;
using System.Reflection;

public class Example
{
    public static void Main()
    {
        Type t = typeof(SimpleClass);
        BindingFlags flags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public |
                             BindingFlags.NonPublic | BindingFlags.FlattenHierarchy;
        MemberInfo[] members = t.GetMembers(flags);
        Console.WriteLine($"Type {t.Name} has {members.Length} members: ");
        foreach (var member in members)
        {
            string access = "";
            string stat = "";
            var method = member as MethodBase;
            if (method != null)
            {
                if (method.IsPublic)
                    access = " Public";
                else if (method.IsPrivate)
                    access = " Private";
                else if (method.IsFamily)
                    access = " Protected";
                else if (method.IsAssembly)
                    access = " Internal";
                else if (method.IsFamilyOrAssembly)
                    access = " Protected Internal ";
                if (method.IsStatic)
                    stat = " Static";
            }
            var output = $"{member.Name} ({member.MemberType}): {access}{stat}, Declared by {member.DeclaringType}";
            Console.WriteLine(output);
        }
    }
}
// The example displays the following output:
//	Type SimpleClass has 9 members:
//	ToString (Method):  Public, Declared by System.Object
//	Equals (Method):  Public, Declared by System.Object
//	Equals (Method):  Public Static, Declared by System.Object
//	ReferenceEquals (Method):  Public Static, Declared by System.Object
//	GetHashCode (Method):  Public, Declared by System.Object
//	GetType (Method):  Public, Declared by System.Object
//	Finalize (Method):  Internal, Declared by System.Object
//	MemberwiseClone (Method):  Internal, Declared by System.Object
//	.ctor (Constructor):  Public, Declared by SimpleClass

L’héritage implicite à partir de la classe Object rend ces méthodes disponibles pour la classe SimpleClass :Implicit inheritance from the Object class makes these methods available to the SimpleClass class:

  • La méthode public ToString, qui convertit un objet SimpleClass en sa représentation de chaîne, retourne le nom de type complet.The public ToString method, which converts a SimpleClass object to its string representation, returns the fully qualified type name. Dans ce cas, la méthode ToString retourne la chaîne « SimpleClass ».In this case, the ToString method returns the string "SimpleClass".

  • Voici trois méthodes de test d’égalité de deux objets : la méthode public instance Equals(Object), la méthode public static Equals(Object, Object) et la méthode public static ReferenceEquals(Object, Object).Three methods that test for equality of two objects: the public instance Equals(Object) method, the public static Equals(Object, Object) method, and the public static ReferenceEquals(Object, Object) method. Par défaut, ces méthodes testent l’égalité des références. Autrement dit, pour être égales, deux variables d’objet doivent faire référence au même objet.By default, these methods test for reference equality; that is, to be equal, two object variables must refer to the same object.

  • La méthode public GetHashCode, qui calcule une valeur qui permet à une instance du type d’être utilisée dans des collections hachées.The public GetHashCode method, which computes a value that allows an instance of the type to be used in hashed collections.

  • La méthode GetType publique qui retourne un objet Type qui représente le type SimpleClass.The public GetType method, which returns a Type object that represents the SimpleClass type.

  • La méthode protected Finalize, qui est conçue pour libérer les ressources non gérées avant que la mémoire d’un objet soit récupérée par le récupérateur de mémoire.The protected Finalize method, which is designed to release unmanaged resources before an object's memory is reclaimed by the garbage collector.

  • La méthode protected MemberwiseClone, qui crée un clone partiel de l’objet actuel.The protected MemberwiseClone method, which creates a shallow clone of the current object.

En raison de l’héritage implicite, vous pouvez appeler n’importe quel membre hérité d’un objet SimpleClass exactement comme s’il était en fait un membre défini dans la classe SimpleClass.Because of implicit inheritance, you can call any inherited member from a SimpleClass object just as if it was actually a member defined in the SimpleClass class. Par exemple, l’exemple suivant appelle la méthode SimpleClass.ToString, dont SimpleClass hérite de Object.For instance, the following example calls the SimpleClass.ToString method, which SimpleClass inherits from Object.

using System;

public class SimpleClass
{}

public class Example
{
    public static void Main()
    {
        SimpleClass sc = new SimpleClass();
        Console.WriteLine(sc.ToString());
    }
}
// The example displays the following output:
//        SimpleClass

Le tableau suivant répertorie les catégories de types que vous pouvez créer en C# et les types à partir desquels ils héritent implicitement.The following table lists the categories of types that you can create in C# and the types from which they implicitly inherit. Chaque type de base apporte un autre ensemble de membres disponibles via l’héritage aux types dérivés implicitement.Each base type makes a different set of members available through inheritance to implicitly derived types.

Catégorie de typeType category Hérite implicitement deImplicitly inherits from
classeclass Object
structstruct ValueType, ObjectValueType, Object
enumenum Enum, ValueType, ObjectEnum, ValueType, Object
déléguédelegate MulticastDelegate, Delegate, ObjectMulticastDelegate, Delegate, Object

L’héritage et une relation « est un »Inheritance and an "is a" relationship

En règle générale, l’héritage est utilisé pour exprimer une relation « est un » entre une classe de base et une ou plusieurs classes dérivées, où les classes dérivées sont des versions spécialisées de la classe de base ; la classe dérivée est un type de la classe de base.Ordinarily, inheritance is used to express an "is a" relationship between a base class and one or more derived classes, where the derived classes are specialized versions of the base class; the derived class is a type of the base class. Par exemple, la classe Publication représente une publication de tout type et les classes Book et Magazine représentent les classes des types spécifiques de publications.For example, the Publication class represents a publication of any kind, and the Book and Magazine classes represent specific types of publications.

Notes

Les classes et structures peuvent implémenter une ou plusieurs interfaces.A class or struct can implement one or more interfaces. Bien que l’implémentation d’interface est souvent présentée comme une solution de contournement pour l’héritage unique ou comme une façon d’utiliser l’héritage avec les structures, elle est conçue pour exprimer une autre relation (« peut faire ») entre une interface et son type d’implémentation que l’héritage.While interface implementation is often presented as a workaround for single inheritance or as a way of using inheritance with structs, it is intended to express a different relationship (a "can do" relationship) between an interface and its implementing type than inheritance. Une interface définit un sous-ensemble de fonctionnalités (comme la capacité à tester l’égalité, comparer ou trier des objets, ou pour prendre en charge la mise en forme et l’analyse dépendant de la culture) que l’interface met à disposition pour ses types d’implémentation.An interface defines a subset of functionality (such as the ability to test for equality, to compare or sort objects, or to support culture-sensitive parsing and formatting) that the interface makes available to its implementing types.

Notez que « est un » exprime également la relation entre un type et une instanciation spécifique de ce type.Note that "is a" also expresses the relationship between a type and a specific instantiation of that type. Dans l’exemple suivant, Automobile est une classe qui possède trois propriétés en lecture seule uniques : Make, le fabricant de l’automobile ; Model, le type de voiture et Year, son année de fabrication.In the following example, Automobile is a class that has three unique read-only properties: Make, the manufacturer of the automobile; Model, the kind of automobile; and Year, its year of manufacture. Votre classe Automobile comporte également un constructeur dont les arguments sont assignés aux valeurs de propriété, et elle remplace la méthode Object.ToString pour générer une chaîne qui identifie de façon unique l’instance Automobile plutôt que la classe Automobile.Your Automobile class also has a constructor whose arguments are assigned to the property values, and it overrides the Object.ToString method to produce a string that uniquely identifies the Automobile instance rather than the Automobile class.

using System;

public class Automobile
{
    public Automobile(string make, string model, int year)
    {
        if (make == null)
           throw new ArgumentNullException("The make cannot be null.");
        else if (String.IsNullOrWhiteSpace(make))
           throw new ArgumentException("make cannot be an empty string or have space characters only.");
        Make = make;

        if (model == null)
           throw new ArgumentNullException("The model cannot be null.");
        else if (String.IsNullOrWhiteSpace(model))
           throw new ArgumentException("model cannot be an empty string or have space characters only.");
        Model = model;

        if (year < 1857 || year > DateTime.Now.Year + 2)
           throw new ArgumentException("The year is out of range.");
        Year = year;
    }

    public string Make { get; }
    
    public string Model { get; }

    public int Year { get; }

    public override string ToString() => $"{Year} {Make} {Model}";
}

Dans ce cas, vous ne devriez pas vous reposer sur l’héritage pour représenter les modèles et constructeurs spécifiques.In this case, you shouldn't rely on inheritance to represent specific car makes and models. Par exemple, il est inutile de définir un type Packard pour représenter les véhicules automobiles fabriqués par la société Packard Motor Car.For example, you don't need to define a Packard type to represent automobiles manufactured by the Packard Motor Car Company. Au lieu de cela, vous pouvez les représenter en créant un objet Automobile avec les valeurs appropriées passées à son constructeur de classe, comme dans l’exemple suivant.Instead, you can represent them by creating an Automobile object with the appropriate values passed to its class constructor, as the following example does.

using System;

public class Example
{
    public static void Main()
    {
        var packard = new Automobile("Packard", "Custom Eight", 1948);
        Console.WriteLine(packard);
    }
}
// The example displays the following output:
//        1948 Packard Custom Eight

Une relation « est un » basée sur l’héritage est préférablement appliquée à une classe de base et aux classes dérivées qui ajoutent des membres supplémentaires à la classe de base ou qui nécessitent des fonctionnalités supplémentaires non présentes dans la classe de base.An is-a relationship based on inheritance is best applied to a base class and to derived classes that add additional members to the base class or that require additional functionality not present in the base class.

Conception de la classe de base et des classes dérivéesDesigning the base class and derived classes

Examinons le processus de conception d’une classe de base et de ses classes dérivées.Let's look at the process of designing a base class and its derived classes. Dans cette section, vous allez définir une classe de base, Publication, qui représente une publication de tout type, tel qu’un livre, un magazine, un journal, un journal, un article, etc. Vous définirez également une classe Book qui dérive de Publication.In this section, you'll define a base class, Publication, which represents a publication of any kind, such as a book, a magazine, a newspaper, a journal, an article, etc. You'll also define a Book class that derives from Publication. Vous pourriez facilement étendre l’exemple pour définir d’autres classes dérivées, comme Magazine, Journal, Newspaper et Article.You could easily extend the example to define other derived classes, such as Magazine, Journal, Newspaper, and Article.

Classe Publication de baseThe base Publication class

Lors de la conception de votre classe Publication, vous devez prendre plusieurs décisions de conception :In designing your Publication class, you need to make several design decisions:

  • Les membres à inclure dans votre classe de base Publication et si les membres Publication fournissent des implémentations de méthode, ou si Publication est une classe de base abstraite qui sert de modèle pour ses classes dérivées.What members to include in your base Publication class, and whether the Publication members provide method implementations or whether Publication is an abstract base class that serves as a template for its derived classes.

    Dans ce cas, la classe Publication fournit des implémentations de méthode.In this case, the Publication class will provide method implementations. La section Conception de classes de base abstraites et leurs classes dérivées contient un exemple qui utilise une classe de base abstraite pour définir les méthodes que les classes dérivées doivent substituer.The Designing abstract base classes and their derived classes section contains an example that uses an abstract base class to define the methods that derived classes must override. Les classes dérivées sont libres de fournir une implémentation qui convient pour le type dérivé.Derived classes are free to provide any implementation that is suitable for the derived type.

    La possibilité de réutiliser le code (autrement dit, plusieurs classes dérivées partagent la déclaration et l’implémentation de méthodes de classe de base et n’ont pas besoin de les substituer) constitue un avantage des classes de base non abstraites.The ability to reuse code (that is, multiple derived classes share the declaration and implementation of base class methods and do not need to override them) is an advantage of non-abstract base classes. Par conséquent, vous devez ajouter des membres à Publication si leur code est susceptible d’être partagé par certains ou la majorité des types Publication spécialisés.Therefore, you should add members to Publication if their code is likely to be shared by some or most specialized Publication types. Si vous ne fournissez pas efficacement les implémentations de classe de base, vous devrez fournir des implémentations de membres en grande partie identiques dans les classes dérivées au lieu d’une implémentation unique dans la classe de base.If you fail to provide base class implementations efficiently, you'll end up having to provide largely identical member implementations in derived classes rather a single implementation in the base class. La nécessité de maintenir le code dupliqué à plusieurs emplacements est une source potentielle de bogues.The need to maintain duplicated code in multiple locations is a potential source of bugs.

    Pour optimiser la réutilisation du code et créer une hiérarchie d’héritage logique et intuitive, vous voulez vous assurer d’ajouter à la classe Publication uniquement les données et fonctionnalités communes à toutes les publications ou la plupart d’entre elles.Both to maximize code reuse and to create a logical and intuitive inheritance hierarchy, you want to be sure that you include in the Publication class only the data and functionality that is common to all or to most publications. Les classes dérivées implémentent ensuite les membres qui sont uniques pour les types particuliers de publications qu’ils représentent.Derived classes then implement members that are unique to the particular kinds of publication that they represent.

  • La mesure dans laquelle étendre votre hiérarchie de classes.How far to extend your class hierarchy. Souhaitez-vous développer une hiérarchie de trois classes ou plus, plutôt que simplement une classe de base et une ou plusieurs classes dérivées ?Do you want to develop a hierarchy of three or more classes, rather than simply a base class and one or more derived classes? Par exemple, Publication peut être une classe de base de Periodical, qui est elle-même une classe de base de Magazine, Journal et Newspaper.For example, Publication could be a base class of Periodical, which in turn is a base class of Magazine, Journal and Newspaper.

    Dans votre exemple, vous allez utiliser la hiérarchie simple d’une classe Publication et d’une classe dérivée unique, Book.For your example, you'll use the small hierarchy of a Publication class and a single derived class, Book. Vous pourriez facilement étendre l’exemple pour créer un certain nombre d’autres classes qui dérivent de Publication, comme Magazine et Article.You could easily extend the example to create a number of additional classes that derive from Publication, such as Magazine and Article.

  • S’il est judicieux d’instancier la classe de base.Whether it makes sense to instantiate the base class. Si ce n’est pas le cas, vous devez appliquer le mot-clé abstract à la classe.If it does not, you should apply the abstract keyword to the class. Dans le cas contraire, votre classe Publication peut être instanciée en appelant son constructeur de classe.Otherwise, your Publication class can be instantiated by calling its class constructor. Si une tentative est faite pour instancier une classe marquée avec le mot-clé abstract par un appel direct à son constructeur de classe, le compilateur C# génère l’erreur CS0144, « Impossible de créer une instance de la classe ou interface abstraite ».If an attempt is made to instantiate a class marked with the abstract keyword by a direct call to its class constructor, the C# compiler generates error CS0144, "Cannot create an instance of the abstract class or interface." Si une tentative est faite pour instancier la classe à l’aide de la réflexion, la méthode de la réflexion lève une exception MemberAccessException.If an attempt is made to instantiate the class by using reflection, the reflection method throws a MemberAccessException.

    Par défaut, une classe de base peut être instanciée en appelant son constructeur de classe.By default, a base class can be instantiated by calling its class constructor. Vous n’avez pas à définir explicitement un constructeur de classe.You do not have to explicitly define a class constructor. S’il n’y en a aucun présent dans le code source de la classe de base, le compilateur C# fournit automatiquement un constructeur par défaut (sans paramètre).If one is not present in the base class' source code, the C# compiler automatically provides a default (parameterless) constructor.

    Dans votre exemple, vous marquez la classe Publication comme abstract afin qu’elle ne puisse pas être instanciée.For your example, you'll mark the Publication class as abstract so that it cannot be instantiated. Une classe abstract sans méthode abstract indique que cette classe représente un concept abstrait qui est partagé entre plusieurs classes concrètes (comme Book, Journal).An abstract class without any abstract methods indicates that this class represents an abstract concept that is shared among several concrete classes (like a Book, Journal).

  • Si les classes dérivées doivent hériter de l’implémentation de classe de base de membres particuliers, si elles ont l’option de substituer l’implémentation de la classe de base ou si elles doivent fournir une implémentation.Whether derived classes must inherit the base class implementation of particular members, whether they have the option to override the base class implementation, or whether they must provide an implementation. Vous utilisez le mot clé abstract pour forcer les classes dérivées à fournir une implémentation.You use the abstract keyword to force derived classes to provide an implementation. Vous devez utiliser le mot clé virtual pour permettre aux classes dérivées de substituer une méthode de classe de base.You use the virtual keyword to allow derived classes to override a base class method. Par défaut, les méthodes définies dans la classe de base ne sont pas substituables.By default, methods defined in the base class are not overridable.

La classe Publication n’a aucune méthode abstract, mais la classe elle-même est abstract.The Publication class does not have any abstract methods, but the class itself is abstract.

  • Si une classe dérivée représente la classe finale dans la hiérarchie d’héritage et ne peut pas elle-même être utilisée comme classe de base pour les classes dérivées supplémentaires.Whether a derived class represents the final class in the inheritance hierarchy and cannot itself be used as a base class for additional derived classes. Par défaut, toute classe peut servir de classe de base.By default, any class can serve as a base class. Vous pouvez appliquer le mot clé sealed pour indiquer qu’une classe ne peut pas servir de classe de base pour des classes supplémentaires.You can apply the sealed keyword to indicate that a class cannot serve as a base class for any additional classes. La tentative de dériver à partir d’une classe sealed a généré l’erreur de compilateur CS0509, « impossible de dériver à partir du type sealed <typeName> ».Attempting to derive from a sealed class generated compiler error CS0509, "cannot derive from sealed type <typeName>".

    Dans votre exemple, vous allez marquer votre classe dérivée en tant que sealed.For your example, you'll mark your derived class as sealed.

L’exemple suivant montre le code source pour la classe Publication ainsi qu’une énumération PublicationType retournée par la propriété Publication.PublicationType.The following example shows the source code for the Publication class, as well as a PublicationType enumeration that is returned by the Publication.PublicationType property. Outre les membres qu’elle hérite de Object, la classe Publication définit les membres uniques et substitutions de membres suivants :In addition to the members that it inherits from Object, the Publication class defines the following unique members and member overrides:

using System;

public enum PublicationType { Misc, Book, Magazine, Article };

public abstract class Publication
{
   private bool published = false;
   private DateTime datePublished;
   private int totalPages; 

   public Publication(string title, string publisher, PublicationType type)
   {
      if (publisher == null)
         throw new ArgumentNullException("The publisher cannot be null.");
      else if (String.IsNullOrWhiteSpace(publisher))
         throw new ArgumentException("The publisher cannot consist only of white space.");
      Publisher = publisher;
  
      if (title == null)
         throw new ArgumentNullException("The title cannot be null.");
      else if (String.IsNullOrWhiteSpace(title))
         throw new ArgumentException("The title cannot consist only of white space.");
      Title = title;

      Type = type;
   }

   public string Publisher { get; }

   public string Title { get; }

   public PublicationType Type { get; }

   public string CopyrightName { get; private set; }
   
   public int CopyrightDate { get; private set; }

   public int Pages
   {
     get { return totalPages; }
     set 
     {
         if (value <= 0)
            throw new ArgumentOutOfRangeException("The number of pages cannot be zero or negative.");
         totalPages = value;   
     }
   }

   public string GetPublicationDate()
   {
      if (!published)
         return "NYP";
      else
         return datePublished.ToString("d");   
   }
   
   public void Publish(DateTime datePublished)
   {
      published = true;
      this.datePublished = datePublished;
   }

   public void Copyright(string copyrightName, int copyrightDate)
   {
      if (copyrightName == null)
         throw new ArgumentNullException("The name of the copyright holder cannot be null.");
      else if (String.IsNullOrWhiteSpace(copyrightName))
         throw new ArgumentException("The name of the copyright holder cannot consist only of white space.");
      CopyrightName = copyrightName;
      
      int currentYear = DateTime.Now.Year;
      if (copyrightDate < currentYear - 10 || copyrightDate > currentYear + 2)
         throw new ArgumentOutOfRangeException($"The copyright year must be between {currentYear - 10} and {currentYear + 1}");
      CopyrightDate = copyrightDate;      
   }

   public override string ToString() => Title;
}
  • Un constructeurA constructor

    Étant donné que la classe Publication est abstract, elle ne peut pas être instanciée directement à partir du code comme dans l’exemple suivant :Because the Publication class is abstract, it cannot be instantiated directly from code like the following example:

    var publication = new Publication("Tiddlywinks for Experts", "Fun and Games",
                                      PublicationType.Book);
    

    Toutefois, son constructeur d’instance peut être appelé directement à partir des constructeurs de classes dérivées, comme le code source pour la classe Book le montre.However, its instance constructor can be called directly from derived class constructors, as the source code for the Book class shows.

  • Deux propriétés liées à la publicationTwo publication-related properties

    Title est une propriété String en lecture seule dont la valeur est fournie en appelant le constructeur Publication.Title is a read-only String property whose value is supplied by calling the Publication constructor.

    Pages est une propriété Int32 en lecture seule qui indique le nombre total de pages de la publication.Pages is a read-write Int32 property that indicates how many total pages the publication has. La valeur est stockée dans un champ privé nommé totalPages.The value is stored in a private field named totalPages. Elle doit être positive, sans quoi une exception ArgumentOutOfRangeException est levée.It must be a positive number or an ArgumentOutOfRangeException is thrown.

  • Membres liés à l’éditeurPublisher-related members

    Deux propriétés en lecture seule, Publisher et Type.Two read-only properties, Publisher and Type. Les valeurs sont à l’origine fournies par l’appel au constructeur de la classe Publication.The values are originally supplied by the call to the Publication class constructor.

  • Membres liés à la publicationPublishing-related members

    Deux méthodes, Publish et GetPublicationDate définissent et retournent la date de publication.Two methods, Publish and GetPublicationDate, set and return the publication date. La méthode Publish définit l’indicateur privé published sur true lorsqu’elle est appelée et affecte la date passée comme argument au champ privé datePublished.The Publish method sets a private published flag to true when it is called and assigns the date passed to it as an argument to the private datePublished field. La méthode GetPublicationDate retourne la chaîne « NYP » si l’indicateur published est false, et la valeur du champ datePublished si l’indicateur est true.The GetPublicationDate method returns the string "NYP" if the published flag is false, and the value of the datePublished field if it is true.

  • Membres liés aux droits d’auteurCopyright-related members

    La méthode Copyright prend comme arguments le nom du titulaire des droits d’auteur et l’année des droits d’auteur et les attribue aux propriétés CopyrightName et CopyrightDate.The Copyright method takes the name of the copyright holder and the year of the copyright as arguments and assigns them to the CopyrightName and CopyrightDate properties.

  • Une substitution de la méthode ToStringAn override of the ToString method

    Si un type ne remplace pas la méthode Object.ToString, il retourne le nom qualifié complet du type, ce qui n’aide pas vraiment à faire la différence entre une instance et une autre.If a type does not override the Object.ToString method, it returns the fully qualified name of the type, which is of little use in differentiating one instance from another. La classe Publication substitue Object.ToString pour retourner la valeur de la propriété Title.The Publication class overrides Object.ToString to return the value of the Title property.

Le schéma suivant illustre la relation entre votre classe Publication de base et sa classe Object implicitement héritée.The following figure illustrates the relationship between your base Publication class and its implicitly inherited Object class.

Les classes Object et Publication

La classe BookThe Book class

La classe Book représente un livre sous la forme d’un type spécialisé de publication.The Book class represents a book as a specialized type of publication. L’exemple suivant montre le code source pour la classe Book.The following example shows the source code for the Book class.

using System;

public sealed class Book : Publication
{
   public Book(string title, string author, string publisher) : 
          this(title, String.Empty, author, publisher)
   { }

   public Book(string title, string isbn, string author, string publisher) : base(title, publisher, PublicationType.Book)
   {
      // isbn argument must be a 10- or 13-character numeric string without "-" characters.
      // We could also determine whether the ISBN is valid by comparing its checksum digit 
      // with a computed checksum.
      //
      if (! String.IsNullOrEmpty(isbn)) {
        // Determine if ISBN length is correct.
        if (! (isbn.Length == 10 | isbn.Length == 13))
            throw new ArgumentException("The ISBN must be a 10- or 13-character numeric string.");
        ulong nISBN = 0;
        if (! UInt64.TryParse(isbn, out nISBN))
            throw new ArgumentException("The ISBN can consist of numeric characters only.");
      } 
      ISBN = isbn;

      Author = author;
   }
     
   public string ISBN { get; }

   public string Author { get; }
   
   public Decimal Price { get; private set; }

   // A three-digit ISO currency symbol.
   public string Currency { get; private set; }

   // Returns the old price, and sets a new price.
   public Decimal SetPrice(Decimal price, string currency)
   {
       if (price < 0)
          throw new ArgumentOutOfRangeException("The price cannot be negative.");
       Decimal oldValue = Price;
       Price = price;
       
       if (currency.Length != 3)
          throw new ArgumentException("The ISO currency symbol is a 3-character string.");
       Currency = currency;

       return oldValue;      
   }

   public override bool Equals(object obj)
   {
      Book book = obj as Book;
      if (book == null)
         return false;
      else
         return ISBN == book.ISBN;   
   }

   public override int GetHashCode() => ISBN.GetHashCode();

   public override string ToString() => $"{(String.IsNullOrEmpty(Author) ? "" : Author + ", ")}{Title}"; 
}

Outre les membres qu’elle hérite de Publication, la classe Book définit les membres uniques et substitutions de membres suivants :In addition to the members that it inherits from Publication, the Book class defines the following unique members and member overrides:

  • Deux constructeursTwo constructors

    Les deux constructeurs Book partagent trois paramètres communs.The two Book constructors share three common parameters. Deux d’entre eux, title et publisher, correspondent aux paramètres du constructeur Publication.Two, title and publisher, correspond to parameters of the Publication constructor. Le troisième est author, qui est stocké dans une propriété Author non modifiable publique.The third is author, which is stored to a public immutable Author property. Un constructeur inclut un paramètre isbn, qui est stocké dans l’auto-propriété ISBN.One constructor includes an isbn parameter, which is stored in the ISBN auto-property.

    Le premier constructeur utilise le mot-clé this pour appeler l’autre constructeur.The first constructor uses the this keyword to call the other constructor. Le chaînage de constructeurs est un modèle courant pour la définition de constructeurs.Constructor chaining is a common pattern in defining constructors. Les constructeurs avec le moins de paramètres fournissent les valeurs par défaut au moment de l’appel du constructeur avec le plus grand nombre de paramètres.Constructors with fewer parameters provide default values when calling the constructor with the greatest number of parameters.

    Le deuxième constructeur utilise le mot-clé base pour transmettre le titre et le nom de l’éditeur au constructeur de classe de base.The second constructor uses the base keyword to pass the title and publisher name to the base class constructor. Si vous n’effectuez pas un appel explicite à un constructeur de classe de base dans votre code source, le compilateur C# fournit automatiquement un appel au constructeur par défaut ou sans paramètres de la classe de base.If you don't make an explicit call to a base class constructor in your source code, the C# compiler automatically supplies a call to the base class' default or parameterless constructor.

  • Une propriété ISBN en lecture seule qui retourne le numéro ISBN de l’objet Book, un numéro unique à 10 ou 13 chiffres.A read-only ISBN property, which returns the Book object's International Standard Book Number, a unique 10- or 13-digit number. Le numéro ISBN est fourni en tant qu’argument à un des constructeurs Book.The ISBN is supplied as an argument to one of the Book constructors. Le numéro ISBN est stocké dans un champ de stockage privé qui est généré automatiquement par le compilateur.The ISBN is stored in a private backing field, which is auto-generated by the compiler.

  • Une propriété Author en lecture seule.A read-only Author property. Le nom de l’auteur est fourni en tant qu’argument aux deux constructeurs Book et est stocké dans la propriété.The author name is supplied as an argument to both Book constructors and is stored in the property.

  • Deux propriétés en lecture seule relatives au prix, Price et Currency.Two read-only price-related properties, Price and Currency. Leurs valeurs sont fournies comme arguments dans un appel de méthode SetPrice.Their values are provided as arguments in a SetPrice method call. La propriété Currency est le symbole de devise ISO à trois caractères (par exemple, USD pour le dollar américain).The Currency property is the three-digit ISO currency symbol (for example, USD for the U.S. dollar). Les symboles de devise ISO peuvent être récupérés à partir de la propriété ISOCurrencySymbol.ISO currency symbols can be retrieved from the ISOCurrencySymbol property. Ces deux propriétés sont en lecture seule en externe, mais peuvent être définies par du code dans la classe Book.Both of these properties are externally read-only, but both can be set by code in the Book class.

  • Une méthode SetPrice qui définit les valeurs des propriétés Price et Currency.A SetPrice method, which sets the values of the Price and Currency properties. Ces valeurs sont retournées par ces mêmes propriétés.Those values are returned by those same properties.

  • Se substitue à la méthode ToString (héritée de Publication) et aux méthodes Object.Equals(Object) et GetHashCode (héritées de Object).Overrides to the ToString method (inherited from Publication) and the Object.Equals(Object) and GetHashCode methods (inherited from Object).

    Sauf si elle est substituée, la méthode Object.Equals(Object) teste l’égalité des références.Unless it is overridden, the Object.Equals(Object) method tests for reference equality. Autrement dit, deux variables d’objet sont considérées comme égales si elles font référence au même objet.That is, two object variables are considered to be equal if they refer to the same object. Dans la classe Book, en revanche, deux objets Book doivent être égaux s’ils ont le même ISBN.In the Book class, on the other hand, two Book objects should be equal if they have the same ISBN.

    Lorsque vous substituez la méthode Object.Equals(Object), vous devez également substituer la méthode GetHashCode qui retourne une valeur que le runtime utilise pour stocker les éléments dans les collections hachées pour une récupération efficace.When you override the Object.Equals(Object) method, you must also override the GetHashCode method, which returns a value that the runtime uses to store items in hashed collections for efficient retrieval. Le code de hachage doit retourner une valeur qui est cohérente avec le test d’égalité.The hash code should return a value that's consistent with the test for equality. Étant donné que vous avez substitué Object.Equals(Object) pour retourner true si les propriétés ISBN de deux objets Book sont égales, vous retournez le code de hachage calculé en appelant la méthode GetHashCode de la chaîne retournée par la propriété ISBN.Since you've overridden Object.Equals(Object) to return true if the ISBN properties of two Book objects are equal, you return the hash code computed by calling the GetHashCode method of the string returned by the ISBN property.

Le schéma suivant illustre la relation entre la base la classe Book et Publication, sa classe de base.The following figure illustrates the relationship between the Book class and Publication, its base class.

Les classes Publication et Book

Vous pouvez maintenant instancier un objet Book, appeler ses membres uniques et hérités le passer en tant qu’argument pour une méthode qui attend un paramètre de type Publication ou de type Book, comme illustré dans l’exemple suivant.You can now instantiate a Book object, invoke both its unique and inherited members, and pass it as an argument to a method that expects a parameter of type Publication or of type Book, as the following example shows.

using System;
using static System.Console;

public class Example
{
   public static void Main()
   {
      var book = new Book("The Tempest",  "0971655819", "Shakespeare, William",
                          "Public Domain Press");
      ShowPublicationInfo(book);
      book.Publish(new DateTime(2016, 8, 18));
      ShowPublicationInfo(book);

      var book2 = new Book("The Tempest", "Classic Works Press", "Shakespeare, William");
      Write($"{book.Title} and {book2.Title} are the same publication: " +
            $"{((Publication) book).Equals(book2)}");
   }

   public static void ShowPublicationInfo(Publication pub)
   {
       string pubDate = pub.GetPublicationDate();
       WriteLine($"{pub.Title}, " +
                 $"{(pubDate == "NYP" ? "Not Yet Published" : "published on " + pubDate):d} by {pub.Publisher}"); 
   }
}
// The example displays the following output:
//        The Tempest, Not Yet Published by Public Domain Press
//        The Tempest, published on 8/18/2016 by Public Domain Press
//        The Tempest and The Tempest are the same publication: False

Conception de classes de base abstraites et de leurs classes dérivéesDesigning abstract base classes and their derived classes

Dans l’exemple précédent, vous avez défini une classe de base qui a fourni une implémentation d’un certain nombre de méthodes pour permettre aux classes dérivées de partager du code.In the previous example, you defined a base class that provided an implementation for a number of methods to allow derived classes to share code. Dans de nombreux cas, toutefois, la classe de base n'est pas censée fournir une implémentation.In many cases, however, the base class is not expected to provide an implementation. Au lieu de cela, la classe de base est une classe abstraite qui déclare des méthodes abstraites ; elle sert de modèle qui définit les membres que chaque classe dérivée doit implémenter.Instead, the base class is an abstract class that declares abstract methods; it serves as a template that defines the members that each derived class must implement. En général, dans une classe de base abstraite, l’implémentation de chaque type dérivé est unique pour ce type.Typically in an abstract base class, the implementation of each derived type is unique to that type. Vous avez marqué la classe avec le mot clé abstract, car il n’était pas judicieux d’instancier un objet Publication, même si la classe fournissait des implémentations de fonctionnalités communes aux publications.You marked the class with the abstract keyword because it made no sense to instantiate a Publication object, although the class did provide implementations of functionality common to publications.

Par exemple, chaque forme géométrique bidimensionnelle fermée inclut deux propriétés : l’aire, l’étendue interne de la forme, et le périmètre, ou la distance le long des bords de la forme.For example, each closed two-dimensional geometric shape includes two properties: area, the inner extent of the shape; and perimeter, or the distance along the edges of the shape. La façon de laquelle ces propriétés sont calculées, cependant, dépend entièrement de la forme spécifique.The way in which these properties are calculated, however, depends completely on the specific shape. La formule pour calculer le périmètre (ou la circonférence) d’un cercle, par exemple, est différente de celle d’un triangle.The formula for calculating the perimeter (or circumference) of a circle, for example, is different from that of a triangle. La classe Shape est une classe abstract avec des méthodes abstract.The Shape class is an abstract class with abstract methods. Ceci indique que les classes dérivées partagent les mêmes fonctionnalités, mais ces classes dérivées implémentent ces fonctionnalités différemment.That indicates derived classes share the same functionality, but those derived classes implement that functionality differently.

L’exemple suivant définit une classe de base abstraite nommée Shape qui définit deux propriétés : Area et Perimeter.The following example defines an abstract base class named Shape that defines two properties: Area and Perimeter. En plus de marquer la classe avec le mot clé abstract, chaque membre de l’instance est également marqué avec le mot clé abstract.In addition to marking the class with the abstract keyword, each instance member is also marked with the abstract keyword. Dans ce cas, Shape substitue également la méthode Object.ToString pour renvoyer le nom du type, plutôt que son nom qualifié complet.In this case, Shape also overrides the Object.ToString method to return the name of the type, rather than its fully qualified name. Elle définit aussi deux membres statiques, GetArea et GetPerimeter, qui permettent aux appelants de récupérer facilement l’aire et le périmètre d’une instance de toute classe dérivée.And it defines two static members, GetArea and GetPerimeter, that allow callers to easily retrieve the area and perimeter of an instance of any derived class. Lorsque vous passez une instance d’une classe dérivée à l’une de ces méthodes, le runtime appelle la substitution de la méthode de la classe dérivée.When you pass an instance of a derived class to either of these methods, the runtime calls the method override of the derived class.

using System;

public abstract class Shape
{
   public abstract double Area { get; }
   
   public abstract double Perimeter { get; }
 
   public override string ToString() => GetType().Name;

   public static double GetArea(Shape shape) => shape.Area;

   public static double GetPerimeter(Shape shape) => shape.Perimeter;
}

Vous pouvez ensuite dériver des classes qui représentent des formes spécifiques à partir de Shape.You can then derive some classes from Shape that represent specific shapes. L’exemple suivant définit trois classes : Triangle, Rectangle et Circle.The following example defines three classes, Triangle, Rectangle, and Circle. Chaque forme utilise une formule unique pour calculer l’aire et périmètre.Each uses a formula unique for that particular shape to compute the area and perimeter. Certaines des classes dérivées définissent également des propriétés, telles que Rectangle.Diagonal et Circle.Diameter, qui sont propres à la forme qu’ils représentent.Some of the derived classes also define properties, such as Rectangle.Diagonal and Circle.Diameter, that are unique to the shape that they represent.

using System;

public class Square : Shape
{
   public Square(double length)
   {
      Side = length;
   }

   public double Side { get; }  

   public override double Area => Math.Pow(Side, 2); 

   public override double Perimeter => Side * 4;

   public double Diagonal => Math.Round(Math.Sqrt(2) * Side, 2); 
}

public class Rectangle : Shape
{
   public Rectangle(double length, double width)
   {
      Length = length;
      Width = width;
   }

   public double Length { get; }

   public double Width { get; }

   public override double Area => Length * Width;

   public override double Perimeter => 2 * Length + 2 * Width;  

   public bool IsSquare() => Length == Width;

   public double Diagonal => Math.Round(Math.Sqrt(Math.Pow(Length, 2) + Math.Pow(Width, 2)), 2); 
}

public class Circle : Shape
{
   public Circle(double radius)
   {
      Radius = radius;
   } 

   public override double Area => Math.Round(Math.PI * Math.Pow(Radius, 2), 2); 

   public override double Perimeter => Math.Round(Math.PI * 2 * Radius, 2); 

   // Define a circumference, since it's the more familiar term.
   public double Circumference => Perimeter; 

   public double Radius { get; }

   public double Diameter => Radius * 2; 
}

L'exemple suivant utilise les objets dérivés de Shape.The following example uses objects derived from Shape. Elle instancie un tableau d’objets dérivés de Shape et appelle les méthodes statiques de la classe Shape qui encapsule les valeurs de propriété de retour de Shape.It instantiates an array of objects derived from Shape and calls the static methods of the Shape class, which wraps return Shape property values. Le runtime récupère les valeurs de propriétés substituées des types dérivés.The runtime retrieves values from the overridden properties of the derived types. L’exemple convertit également chaque objet Shape dans le tableau en son type dérivé et, si la conversion réussit, récupère les propriétés de cette sous-classe particulière de Shape.The example also casts each Shape object in the array to its derived type and, if the cast succeeds, retrieves properties of that particular subclass of Shape.

using System;

public class Example
{
   public static void Main()
   {
      Shape[] shapes = { new Rectangle(10, 12), new Square(5),
                        new Circle(3) };
      foreach (var shape in shapes) {
         Console.WriteLine($"{shape}: area, {Shape.GetArea(shape)}; " +
                           $"perimeter, {Shape.GetPerimeter(shape)}");
         var rect = shape as Rectangle;
         if (rect != null) {
            Console.WriteLine($"   Is Square: {rect.IsSquare()}, Diagonal: {rect.Diagonal}");
            continue;
         }
         var sq = shape as Square;
         if (sq != null) {
            Console.WriteLine($"   Diagonal: {sq.Diagonal}");
            continue;
         }
      }   
   }
}
// The example displays the following output:
//         Rectangle: area, 120; perimeter, 44
//            Is Square: False, Diagonal: 15.62
//         Square: area, 25; perimeter, 20
//            Diagonal: 7.07
//         Circle: area, 28.27; perimeter, 18.85

Voir aussiSee also