Partager via


Conception de constructeurs

Les constructeurs représentent des méthodes spéciales visant à initialiser des types et à créer des instances de types. Un constructeur de type sert à initialiser des données statiques dans un type. Il est appelé par le Common Language Runtime (CLR) avant de créer des instances du type. Les constructeurs de type sont static (Shared en Visual Basic) et ne peuvent pas prendre de paramètres. Un constructeur d'instance est utilisé pour créer des instances d'un type. Les constructeurs d'instance peuvent prendre des paramètres, mais ce n'est pas indispensable. Un constructeur d'instance sans paramètre est appelé constructeur par défaut.

Les règles suivantes décrivent les méthodes conseillées pour créer des constructeurs.

Privilégiez les constructeurs simples, voire les constructeurs par défaut. Un constructeur simple possède très peu de paramètres et tous les paramètres sont des types primitifs ou des énumérations.

Envisagez d'utiliser une méthode de fabrique statique au lieu d'un constructeur si la sémantique de l'opération requise ne correspond pas directement à la construction d'une nouvelle instance ou si les règles de conception du constructeur ne vous semblent pas naturelles.

Utilisez les paramètres des constructeurs en tant que raccourcis pour définir les propriétés principales.

La définition des propriétés à l'aide du constructeur doit être identique à la définition directe des propriétés. L'exemple de code suivant illustre une classe EmployeeRecord qui peut être initialisée soit par l'appel à un constructeur, soit par la définition directe des propriétés. La classe EmployeeManagerConstructor illustre l'initialisation d'un objet EmployeeRecord à l'aide du constructeur. La classe EmployeeManagerProperties illustre l'initialisation d'un objet EmployeeRecord à l'aide de propriétés. La classe Tester montre que les objets ont le même état, indépendamment de la technique utilisée.

Imports System
Imports System.Collections.ObjectModel
namespace Examples.DesignGuidelines.Constructors

    ' This Class can get its data either by setting 
    ' properties or by passing the data to its constructor.
    Public Class EmployeeRecord

        private employeeIdValue as Integer
        private departmentValue as Integer

        Public Sub New()
        End Sub

        Public Sub New(id as Integer, department as Integer)
            Me.employeeIdValue = id
            Me.departmentValue = department
        End Sub 

        Public Property Department as Integer
            Get 
                Return departmentValue
            End Get
            Set 
                departmentValue = value
            End Set
        End Property

        Public Property EmployeeId as Integer
            Get 
                Return employeeIdValue
            End Get
            Set 
                employeeIdValue = value
            End Set
        End Property

        Public Sub DisplayData()
            Console.WriteLine("{0} {1}", EmployeeId, Department)
        End Sub
    End Class

    ' This Class creates Employee records by passing 
    ' argumemnts to the constructor.
    Public Class EmployeeManagerConstructor
        Dim employees as Collection(Of EmployeeRecord) =  _
            new Collection(Of EmployeeRecord)()

        Public Sub AddEmployee(employeeId as Integer, department as Integer)
            Dim record as EmployeeRecord = new EmployeeRecord(employeeId, department)
            employees.Add(record)
            record.DisplayData()
        End Sub
    End Class

    ' This Class creates Employee records by setting properties.
    Public Class EmployeeManagerProperties
        Dim employees as Collection(Of EmployeeRecord)=  _
        new Collection(Of EmployeeRecord)()
        Public Sub AddEmployee(employeeId as Integer, department as Integer)
            Dim record as EmployeeRecord = new EmployeeRecord()
            record.EmployeeId = employeeId
            record.Department = department
            employees.Add(record)
            record.DisplayData()
        End Sub
    End Class

    Public Class Tester
    ' The following method creates objects with the same state
        ' using the two different approaches.
        Public Shared Sub Main()
            Dim byConstructor as EmployeeManagerConstructor = _
                new EmployeeManagerConstructor()
            byConstructor.AddEmployee(102, 102)

            Dim byProperties as EmployeeManagerProperties = _
                new EmployeeManagerProperties()
            byProperties.AddEmployee(102, 102)
        End Sub
    End Class
End Namespace
using System;
using System.Collections.ObjectModel;
namespace Examples.DesignGuidelines.Constructors
{
    // This class can get its data either by setting 
    // properties or by passing the data to its constructor.
    public class EmployeeRecord
    {
        private int employeeId;
        private int department;

        public EmployeeRecord()
        {
        }
        public EmployeeRecord(int id, int department)
        {
            this.employeeId = id;
            this.department = department;
        }
        public int Department
        {
            get {return department;}
            set {department = value;}
        }
        public int EmployeeId
        {
            get {return employeeId;}
            set {employeeId = value;}
        }
        public void DisplayData()
        {
            Console.WriteLine("{0} {1}", EmployeeId, Department);
        }
    }
    // This class creates Employee records by passing 
    // argumemnts to the constructor.
    public class EmployeeManagerConstructor
    {
        Collection<EmployeeRecord > employees = new Collection<EmployeeRecord>();

        public void AddEmployee(int employeeId, int department)
        {
            EmployeeRecord record = new EmployeeRecord(employeeId, department);
            employees.Add(record);
            record.DisplayData();
        }
    }
    // This class creates Employee records by setting properties.
    public class EmployeeManagerProperties
    {
    Collection<EmployeeRecord > employees = new Collection<EmployeeRecord>();
        public void AddEmployee(int employeeId, int department)
        {
            EmployeeRecord record = new EmployeeRecord();
            record.EmployeeId = employeeId;
            record.Department = department;
            employees.Add(record);
            record.DisplayData();
        }
    }
    public class Tester
    {
    // The following method creates objects with the same state
        // using the two different approaches.
        public static void Main()
        {
            EmployeeManagerConstructor byConstructor = 
                new EmployeeManagerConstructor();
            byConstructor.AddEmployee(102, 102);

            EmployeeManagerProperties byProperties = 
                new EmployeeManagerProperties();
            byProperties.AddEmployee(102, 102);
        }
    }
}
using namespace System;
using namespace System::Collections::ObjectModel;

namespace Examples { namespace DesignGuidelines { namespace Constructors
{
    // This class can get its data either by setting 
    // properties or by passing the data to its constructor.
    public ref class EmployeeRecord
    {
    private:
        int employeeId;
        int department;

    public:
        EmployeeRecord()
        {
        }

        EmployeeRecord(int id, int department)
        {
            this->employeeId = id;
            this->department = department;
        }

        property int Department
        {
            int get() {return department;}
            void set(int value) {department = value;}
        }

        property int EmployeeId
        {
            int get() {return employeeId;}
            void set(int value) {employeeId = value;}
        }

        void DisplayData()
        {
            Console::WriteLine("{0} {1}", EmployeeId, Department);
        }
    };

    // This class creates Employee records by passing 
    // argumemnts to the constructor.
    public ref class EmployeeManagerConstructor
    {
    private:
        Collection<EmployeeRecord^>^ employees;

    public:
        EmployeeManagerConstructor()
        {
            employees = gcnew Collection<EmployeeRecord^>();
        }

        void AddEmployee(int employeeId, int department)
        {
            EmployeeRecord^ record = gcnew EmployeeRecord(employeeId, department);
            employees->Add(record);
            record->DisplayData();
        }
    };

    // This class creates Employee records by setting properties.
    public ref class EmployeeManagerProperties
    {
    private:
        Collection<EmployeeRecord^>^ employees;

    public:
        EmployeeManagerProperties()
        {
            employees = gcnew Collection<EmployeeRecord^>();
        }

        void AddEmployee(int employeeId, int department)
        {
            EmployeeRecord^ record = gcnew EmployeeRecord();
            record->EmployeeId = employeeId;
            record->Department = department;
            employees->Add(record);
            record->DisplayData();
        }
    };

    public ref class Tester
    {
    // The following method creates objects with the same state
        // using the two different approaches.
    public:
        static void Main()
        {
            EmployeeManagerConstructor^ byConstructor =
                gcnew EmployeeManagerConstructor();
            byConstructor->AddEmployee(102, 102);

            EmployeeManagerProperties^ byProperties =
                gcnew EmployeeManagerProperties();
            byProperties->AddEmployee(102, 102);
        }
    };
}}}

Notez que, dans ces exemples et dans une bibliothèque bien conçue, les deux approches créent des objets présentant le même état. L'approche choisie par le développeur importe peu.

Utilisez le même nom pour les paramètres de constructeur et une propriété, si les paramètres de constructeur sont utilisés pour définir simplement la propriété. La seule différence entre ces paramètres et les propriétés est la casse.

Cette règle est illustrée dans l'exemple précédent :

Limitez au maximum les opérations dans le constructeur. Les constructeurs ne devraient rien faire d'autre que capturer les paramètres de constructeur. Le coût de tout autre traitement doit être différé tant qu'il n'est pas indispensable.

Levez des exceptions à partir des constructeurs d'instances, le cas échéant.

Les constructeurs doivent lever et gérer des exceptions comme une méthode quelconque. En particulier, un constructeur ne doit pas intercepter ni masquer des exceptions qu'il ne peut pas gérer. Pour plus d'informations sur les exceptions, consultez Instructions de conception pour les exceptions.

Déclarez explicitement le constructeur public par défaut dans les classes, si un tel constructeur est nécessaire.

Il s'agit de la méthode conseillée pour définir explicitement un constructeur par défaut si votre classe prend cette opération en charge. Même si certains compilateurs ajoutent automatiquement un constructeur par défaut à votre classe, l'ajout explicite de celui-ci simplifie la maintenance du code. En outre, vous êtes assuré que le constructeur par défaut reste défini même si le compilateur cesse de l'émettre parce que vous ajoutez un constructeur avec des paramètres.

Évitez la présence de constructeurs par défaut sur les structures.

De nombreux compilateurs, y compris le compilateur C#, ne prennent pas en charge les constructeurs sans paramètre sur les structures.

N'appelez pas de membres virtuels sur un objet à l'intérieur de ses constructeurs.

Lors de l'appel à un membre virtuel, la substitution la plus dérivée est appelée, que le constructeur du type définissant la substitution la plus dérivée ait été appelé ou non. L'exemple de code suivant illustre ce problème. Au moment où le constructeur de la classe de base s'exécute, il appelle le membre de la classe dérivée, même si le constructeur de la classe dérivée n'a pas été appelé. Cet exemple imprime BadBaseClass pour montrer que le champ d'état n'a pas été mis à jour par le constructeur DerivedFromBad.

Imports System

Namespace Examples.DesignGuidelines.MemberDesign
    Public Class BadBaseClass

        Protected  state as String
        Public Sub New()

            state = "BadBaseClass"
            SetState()
        End Sub
        Public Overridable Sub SetState()
        End Sub
    End Class

    Public Class DerivedFromBad 
        Inherits BadBaseClass
        Public Sub New()

            state = "DerivedFromBad "
        End Sub

        Public Overrides Sub SetState()
            Console.WriteLine(state)
        End Sub
    End Class

    Public Class tester

        Public Shared Sub Main()

            Dim b as DerivedFromBad = new DerivedFromBad()
        End Sub
    End Class
End Namespace
using System;

namespace Examples.DesignGuidelines.MemberDesign
{
    public class BadBaseClass
    {
        protected string state;
        public BadBaseClass()
        {
            state = "BadBaseClass";
            SetState();
        }
        public virtual void SetState()
        {

        }
    }

    public class DerivedFromBad : BadBaseClass
    {
        public DerivedFromBad()
        {
            state = "DerivedFromBad ";
        }
        public override void SetState()
        {
            Console.WriteLine(state);
        }

    }
    public class tester
    {
        public static void Main()
        {
            DerivedFromBad b = new DerivedFromBad();
        }
    }
}
using namespace System;

namespace Examples { namespace DesignGuidelines { namespace MemberDesign
{
    public ref class BadBaseClass
    {
    protected:
        String^ state;

    public:
        BadBaseClass()
        {
            state = "BadBaseClass";
            SetState();
        }

        virtual void SetState()
        {

        }
    };

    public ref class DerivedFromBad : public BadBaseClass
    {
    public:
        DerivedFromBad()
        {
            state = "DerivedFromBad ";
        }

        virtual void SetState() override
        {
            Console::WriteLine(state);
        }

    };

    public ref class tester
    {
    public:
        static void Main()
        {
            DerivedFromBad^ b = gcnew DerivedFromBad();
        }
    };
}}}

Portions Copyright 2005 Microsoft Corporation. Tous droits réservés.

Portions Copyright Addison-Wesley Corporation. Tous droits réservés.

Pour plus d'informations sur les règles de conception, consultez « règles de conception d'infrastructure : Conventions idiomes et modèles carnet de bibliothèques réutilisables framework » Krzysztof Cwalina et Brad Abrams, publiés par Addison-Wesley, 2005.

Voir aussi

Concepts

Conception de constructeurs de type

Autres ressources

Instructions de conception des membres

Instructions de conception pour le développement de bibliothèques de classes