Condividi tramite


Progettazione di costruttori

Aggiornamento: novembre 2007

I costruttori sono metodi speciali utilizzati per inizializzare tipi e creare istanze di tipi. Un costruttore di tipo viene utilizzato per inizializzare i dati statici in un tipo. Tale costruttore viene chiamato da Common Language Runtime (CLR) prima che vengano create istanze del tipo. I costruttori di tipo sono static (Shared in Visual Basic) e non possono accettare parametri. Un costruttore di istanza viene utilizzato per creare istanze di un tipo. I costruttori di istanza possono accettare parametri, anche se questi ultimi non sono obbligatori. Un costruttore di istanza senza parametri è detto costruttore predefinito.

Nelle seguenti linee guida vengono descritte le procedure consigliate per la creazione di costruttori.

Utilizzare i parametri di costruttore come tecnica rapida per l'impostazione delle proprietà principali.

L'impostazione di proprietà tramite costruttore dovrebbe avere lo stesso effetto della modalità di impostazione diretta. Nell'esempio di codice riportato di seguito viene illustrata una classe EmployeeRecord che può essere inizializzata chiamando un costruttore o impostando direttamente le proprietà. La classe EmployeeManagerConstructor illustra l'inizializzazione di un oggetto EmployeeRecord mediante il costruttore. La classe EmployeeManagerProperties illustra l'inizializzazione di un oggetto EmployeeRecord mediante le proprietà. La classe Tester dimostra che, indipendentemente dalla tecnica utilizzata, gli oggetti presentano lo stesso stato.

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);
        }
    }
}

Si noti che in questi esempi, e in una libreria progettata accuratamente, entrambi gli approcci consentono la creazione di oggetti con lo stesso stato. Lo sviluppatore ha la libertà di scegliere quello che preferisce.

Utilizzare lo stesso nome per i parametri di costruttore e una proprietà, nel caso in cui tali parametri vengano utilizzati per impostare semplicemente la proprietà. L'unica differenza fra tali parametri e le proprietà dovrebbe consistere nell'utilizzo di maiuscole e minuscole.

Questa linea guida è illustrata nell'esempio precedente.

Generare eccezioni dai costruttori di istanza, se appropriato.

I costruttori devono generare e gestire eccezioni come qualsiasi metodo. In particolare, un costruttore non deve rilevare e nascondere eccezioni che non è in grado di gestire. Per ulteriori informazioni sulle eccezioni, vedere Linee guida di progettazione delle eccezioni.

Dichiarare in modo esplicito il costruttore pubblico predefinito nelle classi, se tale costruttore è necessario.

È opportuno definire in modo esplicito un costruttore predefinito, se supportato dalla classe. Anche se questa operazione viene eseguita automaticamente da alcuni compilatori, l'aggiunta esplicita di un costruttore predefinito consente di facilitare la manutenzione del codice. Inoltre, tale costruttore rimane definito anche se il compilatore non esegue più questa operazione perché viene aggiunto un costruttore che accetta parametri.

Evitare di utilizzare costruttori predefiniti sulle strutture.

Numerosi compilatori, incluso il compilatore C#, non supportano costruttori senza parametri sulle strutture.

Non chiamare membri virtuali su un oggetto all'interno dei relativi costruttori.

Per effetto della chiamata di un membro virtuale, viene chiamato l'override più derivato, indipendentemente dal fatto che sia stato chiamato il costruttore relativo al tipo che definisce l'override più derivato. Questo concetto è illustrato nell'esempio di codice riportato di seguito. Durante l'esecuzione del costruttore della classe base, viene chiamato il membro della classe derivata, anche se il costruttore della classe derivata non è stato chiamato. Nell'esempio viene visualizzato BadBaseClass per indicare che il campo relativo allo stato non è stato aggiornato dal costruttore 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();
        }
    }
}

Portions Copyright 2005 Microsoft Corporation. Tutti i diritti riservati.

Portions Copyright Addison-Wesley Corporation. Tutti i diritti riservati.

Per ulteriori informazioni sulle linee guida di progettazione, consultare il testo "Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries" di Krzysztof Cwalina e Brad Abrams, edito da Addison-Wesley, 2005.

Vedere anche

Concetti

Progettazione di costruttori del tipo

Altre risorse

Linee guida di progettazione dei membri

Linee guida di progettazione per lo sviluppo di librerie di classi