다음을 통해 공유


생성자 디자인

생성자는 형식을 초기화하고 형식의 인스턴스를 만드는 데 사용되는 특수 메서드입니다. 형식 생성자는 형식에서 정적 데이터를 초기화하는 데 사용됩니다. 형식의 인스턴스가 만들어지기 전에는 CLR(공용 언어 런타임)에서 형식 생성자를 호출합니다. 형식 생성자는 static(Visual Basic의 경우 Shared)이며 매개 변수를 사용할 수 없습니다. 인스턴스 생성자는 형식의 인스턴스를 만드는 데 사용됩니다. 인스턴스 생성자는 매개 변수를 사용할 수 있지만 반드시 사용해야 하는 것은 아닙니다. 매개 변수가 없는 인스턴스 생성자는 기본 생성자라고 합니다.

다음 지침은 생성자를 만드는 최선의 방법에 대해 설명합니다.

단순한 기본 생성자를 제공할 수 있습니다. 단순 생성자에는 매개 변수가 매우 적고 모든 매개 변수는 기본 형식 또는 열거형입니다.

원하는 작업의 구문이 새 인스턴스의 생성에 직접 매핑되지 않거나 생성자 디자인 지침을 따를 수 없는 경우 생성자 대신 정적 팩터리 메서드를 사용할 수 있습니다.

생성자 매개 변수를 주 속성 설정을 위한 바로 가기로 사용합니다.

생성자를 사용한 속성 설정은 속성을 직접 설정하는 것과 같습니다. 다음 코드 예제에서는 생성자를 호출하거나 속성을 직접 설정하여 초기화할 수 있는 EmployeeRecord 클래스를 보여 줍니다. EmployeeManagerConstructor 클래스는 생성자를 사용한 EmployeeRecord 개체 초기화 방법을 보여 줍니다. EmployeeManagerProperties 클래스는 속성을 사용한 EmployeeRecord 개체 초기화 방법을 보여 줍니다. Tester 클래스는 사용하는 기술에 관계없이 개체의 상태가 동일함을 보여 줍니다.

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

이 예제와 올바르게 디자인된 라이브러리 모두 같은 상태에서 개체를 만듭니다. 개발자가 선호하는 사용 방법과는 무관합니다.

생성자 매개 변수를 사용하여 속성을 간단하게 설정하는 경우 생성자 매개 변수와 속성에 같은 이름을 사용합니다. 해당 매개 변수와 속성 간의 유일한 차이점은 대/소문자 구분입니다.

이 지침은 이전 예제에서 설명했습니다.

생성자에서는 최소 작업을 수행합니다. 생성자는 생성자 매개 변수를 캡처하는 작업 이외의 다른 작업을 많이 수행해서는 안 됩니다. 다른 처리 비용은 필요할 때까지 지연시켜야 합니다.

필요한 경우 인스턴스 생성자에서 예외를 throw합니다.

생성자는 메서드와 같은 예외를 throw하고 처리해야 합니다. 특히 생성자는 처리할 수 없는 예외를 catch하거나 숨겨서는 안 됩니다. 예외에 대한 자세한 내용은 예외 디자인 지침을 참조하십시오.

해당 생성자가 필요한 경우 클래스에서 공용 기본 생성자를 명시적으로 선언합니다.

클래스에서 지원하는 경우 기본 생성자를 명시적으로 정의하는 것이 가장 좋습니다. 일부 컴파일러에서는 기본 생성자를 자동으로 클래스에 추가하지만 명시적으로 추가하는 경우 코드를 보다 쉽게 유지 관리할 수 있습니다. 또한 사용자가 매개 변수를 사용하는 생성자를 추가하여 컴파일러가 내보내기를 중지하더라도 기본 생성자는 계속 정의된 상태를 유지합니다.

구조체에는 기본 생성자를 사용하지 않습니다.

C# 컴파일러와 같은 여러 컴파일러가 구조체에서 매개 변수 없는 생성자를 지원하지 않습니다.

해당 생성자 내부에서 개체에 대한 가상 멤버를 호출하지 않습니다.

가상 멤버를 호출하면 가장 많이 파생되는 재정의를 정의하는 형식에 대한 생성자의 호출 여부에 관계없이 가장 많이 파생되는 재정의가 호출됩니다. 다음 코드 예제에서는 이 문제에 대해 설명합니다. 기본 클래스 생성자가 실행되면 파생 클래스 생성자가 호출되지 않은 경우라도 파생 클래스 멤버를 호출합니다. 이 예제에서는 DerivedFromBad 생성자에서 상태 필드를 업데이트하지 않았음을 보여 주는 BadBaseClass를 인쇄합니다.

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. All rights reserved.

Portions Copyright Addison-Wesley Corporation. All rights reserved.

디자인 지침에 자세한 내용은 참조를 "Framework 디자인 지침: 규칙, 숙어, 및 재사용에 대 한 패턴입니다.NET 라이브러리"도 서 Krzysztof Cwalina와 Brad Abrams, 게시 Addison-wesley, 2005.

참고 항목

개념

형식 생성자 디자인

기타 리소스

멤버 디자인 지침

클래스 라이브러리 개발을 위한 디자인 지침