C# constructor usage guideline

private constructor는 정적 메소드와 속성 (static method & property)만 있는 경우 사용함.
http://msdn.microsoft.com/en-us/library/vstudio/kcfb85a6.aspx


public class Counter
{
    private Counter() { }
    public static int currentCount;
    public static int IncrementCount()
    {
        return ++currentCount;
    }
}

class TestCounter
{
    static void Main()
    {
        // If you uncomment the following statement, it will generate
        // an error because the constructor is inaccessible:
        // Counter aCounter = new Counter();   // Error

        Counter.currentCount = 100;
        Counter.IncrementCount();
        Console.WriteLine(“New count: {0}”, Counter.currentCount);

        // Keep the console window open in debug mode.
        Console.WriteLine(“Press any key to exit.”);
        Console.ReadKey();
    }
}
// Output: New count: 101


protected constructor는 추상클래스 (abstract class)에서 사용을 권고함. 추상 클래스를 상속받는 파생클래스에서 파생 클래스 생성자가 부모 클래스 즉, 추상 클래스를 초기화 하기 위해 추상 클래스 생성자를 호출 할 수 있도록 지원함.
http://msdn.microsoft.com/en-us/library/bcd5672a%28v=vs.80%29.aspx
http://msdn.microsoft.com/ko-kr/library/ms229047(v=vs.100).aspx


// protected_keyword.cs
using System;
class A
{
    protected int x = 123;
}

class B : A
{
    static void Main()
    {
        A a = new A();
        B b = new B();

        // Error CS1540, because x can only be accessed by
        // classes derived from A.
        // a.x = 10;

       
        // OK, because this class derives from A.
        b.x = 10;  
    }
}


// protected_keyword_2.cs
using System;
class Point
{
    protected int x;
    protected int y;
}

class DerivedPoint: Point
{
    static void Main()
    {
        DerivedPoint dpoint = new DerivedPoint();

        // Direct access to protected members:
        dpoint.x = 10;
        dpoint.y = 15;
        Console.WriteLine(“x = {0}, y = {1}”, dpoint.x, dpoint.y);
    }
}


new vs override Method


    class Base
    {
        public void Print() { Console.WriteLine(“Base Print”); }
    }


    class Derived : Base
    {
        public void Print() { Console.WriteLine(“Derived Print”); }
    }


    class Program
    {
        static void Main(string[] args)
        {
            Base b = new Base();
            Derived d = new Derived();
            Base e = d;
            b.Print(); // Base Print
            d.Print(); // Derived Print (부모클래스의 메소드와 같은 이름으로 메소드를 정의하면 부모의 메소드는 숨겨짐)
            e.Print(); // Base Print (원래 e는 Derived 객체이나 Base 데이타형이므로 Base의 Print 메소드 호출)
        }
    }


new 메소드 새정의 (위의 코드는 아래와 똑같음. new 키워드를 사용하여 명시적으로 명확하게 적어주도록 함)



    class Base
    {
        public void Print() { Console.WriteLine(“Base Print”); }
    }


    class Derived : Base
    {
        public new void Print() { Console.WriteLine(“Derived Print”); } // 부모클래스의 Print 메소드는 새로 정의
        public void BasePrint() { base.Print(); } // 부모클래스의Print는 여전히 사용 가능

    }


    class Program
    {
        static void Main(string[] args)
        {
            Base b = new Base();
            Derived d = new Derived();
            Base e = d;
            b.Print(); // Base Print
            d.Print(); // Derived Print (부모클래스의 메소드와 같은 이름으로 메소드를 새로 정의)
            d.BasePrint();
            e.Print(); // Base Print (원래 e는 Derived 객체이나 Base 데이타형이므로 Base의 Print 메소드 호출)
        }
    }


virtual – override 메소드 재정의 (Method Overriding) run-time에서 객체의 DataType에 따른 late-binding이 일어남



    class Base
    {
        public virtual void Print() { Console.WriteLine(“Base Print”); }
    }


    class Derived : Base
    {
        public override void Print() { Console.WriteLine(“Derived Print”); } // 부모클래스의 Print 메소드는 재정의
        public void BasePrint() { base.Print(); } // 부모클래스의Print는 여전히 사용 가능

    }


    class Program
    {
        static void Main(string[] args)
        {
            Base b = new Base();
            Derived d = new Derived();
            Base e = d;
            b.Print(); // Base Print
            d.Print(); // Derived Print (부모클래스의 메소드와 같은 이름으로 메소드를 재정의)
            d.BasePrint();
            e.Print(); // Derived Print (원래 e는 Derived 객체이므로 late-binding에 의해서 Base의 Print 메소드 호출)
        }
    }


Protected


    class Car
    {
        // member field
        private bool disel;     // disel은 파생 클래스에서 사용하지 못함
        protected bool gasoline;// gasoline은 파생 클래스에서 사용가능하나 클래스 외부에서는 호출하지 못함
        protected int wheel = 4;// wheel은 파생 클래스에서 사용가능하나 클래스 외부에서는 호출하지 못함


        // constructor
        protected Car() { disel = true; gasoline = true;  }
        protected Car(int wheel) { this.wheel = wheel; disel = false; gasoline = false; }


        // method
        protected void Move()
        {
            if (disel)
                Console.Write(“Car 디젤 “);
            Console.WriteLine(“바퀴 {0} 자동차가 굴러다닌다”, wheel);
        }
    }


    class Sedan : Car
    {
        // member field
        private bool gasoline;  // 파생 클래스에서 기반클래스에 멤버필드명이 같다면 default는 자신의 멤버부터 호출 &
Sedan.gasoline은 Car.gasoline을 숨김 => private new bool gasoline와 같은 의미


        // constructor
        public Sedan() { gasoline = false;  }                      // Sedan() : base() 호출
        public Sedan(int wheel) : base(wheel) { gasoline = true; } // Sedan(int wheel) :
base(int wheel)를 호출 – protected 생성자는 기반 클래스의 생성자 호출 base에서 사용됨


        // method
        public void SedanMove()
        {
            if (base.gasoline)                              // base의 gasoline과 this의 gasoline을 구분해야하는 경우
                Console.Write(“Car 가솔린 “);
            if (this.gasoline)
                Console.Write(“SedanCar 가솔린 “);
            Console.WriteLine(“바퀴 {0} 승용차가 굴러다닌다”, wheel);
        }


        static void Main(string[] args)
        {
            // error CS1540: ‘Car’형식의 한정자를 통해 보호된 ‘Car.Car()’ 멤버에 액세스할 수 없습니다. 한정자는 ‘Sedan’ 형식이거나 여기에서 파생된 형식이어야 합니다.
            //Car myCar = new Car();    // 기반 클래스 생성자 Car()는 상속되지 않음. 따라서 new를 이용하여 객체를 생성할 수 없음.
            //myCar.Move();             //  myCar 객체없이 myCar.Move() 호출할 수 없음
            //Console.WriteLine(“마이카의 바퀴는 {0}개 이다.”, myCar.wheel); // myCar 객체없이 myCar.wheel 호출할 수 없음


            // 바퀴 4개 디젤 자동차
            Sedan myCar1 = new Sedan();
            myCar1.Move();       // Car를 상속받았기 때문에 Move() 메소드를 사용할 수 있음
            myCar1.SedanMove();  // Sedan 자신의 메소드 사용가능
            Console.WriteLine(“마이카의 바퀴는 {0}개 이다.”, myCar1.wheel); // 상속된 객체에서 기반 객체의 protected 멤버 필드 호출가능


            Console.WriteLine();


            // 바퀴 6개 가솔린 자동차
            Sedan myCar2 = new Sedan(6);
            myCar2.Move();       // Car를 상속받았기 때문에 Move() 메소드를 사용할 수 있음
            myCar2.SedanMove();  // Sedan 자신의 메소드 사용가능
            Console.WriteLine(“마이카의 바퀴는 {0}개 이다.”, myCar2.wheel); // 상속된 객체에서 기반 객체의 protected 멤버 필드 호출가능
        }
    }


BankAccount Class


class BankAccount
    {
        double balance;
        string name;
        static double interest;


        public BankAccount() : this(1000, “HCI”)
        {
        }


        public BankAccount(double balance, string name)
        {
            this.balance = balance;
            this.name = name;
            BankAccount.interest = 0.7; // 0.7%
        }


        public void Deposit(double amount)
        {
            balance = balance + amount;
        }


        public void Withdrawl(double amount)
        {
            balance = balance – amount;
        }


        public void Print()
        {
            Console.WriteLine(“{0}의 계좌 잔고는 {1}”,
                name, balance + balance * BankAccount.interest * 0.01);
        }


        public static void InterestRate(double interest)
        {
            BankAccount.interest = interest;
        }
    }


    class Program
    {
        static void Main(string[] args)
        {
            BankAccount b = new BankAccount(5000, “HCI222222222222”);
            b.Print();


            b.Deposit(1000);
            b.Print();


            b.Withdrawl(500);
            b.Print();


            BankAccount.InterestRate(1.5); // 1.5%
            b.Print();


            BankAccount b2 = new BankAccount();
            b2.Print();
        }
    }

static class vs singleton design pattern

공용 데이터를 저장하여 사용하고자 할 때, singleton 패턴이나 static 클래스를 사용한다.

싱글톤 패턴 (Singleton design pattern)
-싱글톤 패턴이란 single instance object(해당 클래스의 인스턴스 하나)가 만들어지고, 어디서든지 그 싱글톤에 접근할 수 있도록 하기 위한 패턴

정적 클래스 (Static class)
-static 키워드를 사용한 정적 클래스는 정적 멤버만 포함 가능
-정적 클래스는 new 키워드를 사용하여 정적 클래스의 인스턴스를 생성할 수 없음
-정적 클래스는 봉인 클래스 (sealed class) 임
-static 클래스는 single-instance, global 데이터를 저장하여 사용하는 용도로 적당
-그러나, 싱글톤은 인자(parameter)나 객체(object)로 사용가능하나 정적클래스는 불가능

http://dis.dankook.ac.kr/lectures/hci10/entry/singleton-pattern과-static-class-비교

Instance vs Static Constructor

C#은 두 가지 종류의 constructor, 즉 class constructor(static constructor), instance constructor(non-static constructor)를 지원한다.
http://dis.dankook.ac.kr/lectures/hci10/entry/static-constructor와-instance-constructor-비교

Static Constructor

-static constructor는 static data member를 초기화하는데 사용
-static constructor는 접근 지정자를 쓸수 없음
-static constructor는 인자를 가질 수 없음
-static constructor는 non-static data member를 접근할 수 없음


-static constructor는 non-static data member를 접근할 수 없음


// Test.cs
class Test
{
//Declaration and initialization of static data member
private static int id = 5;
public static int Id
{
get
{
return id;
}
}

public static void print()
{
Console.WriteLine(“Test.id=” + id);
}
}

class Program
{
static void Main(string[] args)
{
Test.print(); // 정적 메소드를 사용하여 Test.id를 출력
}
}

Test.id=5



// Test1.cs
class
Test1
{
private static int id;

// static constructor를 사용하여 Test.id값에 따라서 Test1.id를 지정
static
Test()
{
if
( Test.Id < 10 )
{
id = 20;
}
else
{
id = 100;
}
}

public static void print()
{
Console.WriteLine(“Test.id=” + id);
}
}

class Program
{
static void Main(string[] args)
{
Test1.print(); // 정적 메소드를 사용하여 Test.id를 출력
}
}

Test.id=20 // 정적 생성자 내에서 Test.id=5였기때문에 Test.id=20

Instance Constructor
-instance constructor는 new 키워드를 사용하여 객체 생성에 사용
-instance constructor는 일반적으로 constructor라고 불림
constructor initializer는 생성자들 코드를 간략하게 만들기 위해 사용


public class MySimpleClass
{
public MySimpleClass (int x)
{
Console.WriteLine (x);
}
}


 


// 위의 코드는 컴파일러에서 아래의 코드처럼 해석
public
class MySimpleClass
{
public MySimpleClass (int x) : base()
{
Console.WriteLine (x);
}
}


 


public class MyClass
{
private ArrayList col;
private string name;
public MyClass() : this(0,””) // 생성자 초기화목록을 사용하여 기본 생성자 지정
{
}
public MyClass(int initialCount) : this (initialCount, “”)
{
}
public MyClass(int initialCount, string name)
{
col = (initialCount > 0) ? new ArrayList(initialCount) : new ArrayList();
this.name = name;
}
}


-default constructor가 지정되어 있지 않다면 컴파일러에서 자동 생성해줌


public class MySimpleClass
{
int someMemberVariable;
}
// 위의 코드를 컴파일러에서 아래와 같이 해석함
public class MySimpleClass
{
int someMemberVariable;

public MySimpleClass() : base()
{
}
}

-constructor는 상속되지 않음
public class MyBaseClass
{
public MyBaseClass (int x)
{
}
}

public class MyDerivedClass : MyBaseClass
{
// This constructor itself is okay – it invokes an
// appropriate base class constructor
public MyDerivedClass () : base (5)
{
}

public static void Main()
{
new MyDerivedClass (10); // ERROR: MyDerivedClass는 인자를 받는 생성자가 없음
}
}

 

Instance vs Static Method

Static Method (일면 Class Method)
-메서드 선언에 static 한정자가 있는 경우 해당 메서드를 정적 메서드라고 한다.
-정적 메서드는 class method나 static member field 조작을 위한 메소드이다.
-정적 메서드 내에서 클래스의 instance field나 method는 접근 불가능하다.
-정적 메서드는 특정 인스턴스에서는 작동되지 않으므로, 정적 메서드 내에서 this를 참조하면 컴파일 타임 오류가 발생한다.

Instance Method
-인스턴스 메서드는 클래스의 지정된 인스턴스에서 작동한다.
-인스턴스 메서드 내에서는 this로 액세스할 수 있다.

class ValueClass
{
    private int value = 0;
    public void setValue(int value) { this.value = value; }
    public int getValue() { return this.value; }
    public void print() { Console.WriteLine(“value={0}”, this.value);
    public static void printString(string str) { Console.WriteLine(str); }
}
class Program
{
    static void main(string[] args)
    {
        ValueClass c = new ValueClass();
        c.setValue(10); // 인스턴스 메소드
        c.print(); // 인스턴스 메소드
        ValueClass.printString(“test”); // 정적 메소드 (클래스명.정적메소드명)
    }
}

Instance vs Static Field

Static Field (일명 Class Field)
-전역 데이터, 공유 데이터로 클래스 로딩 시 공간을 할당
-한 클래스에 하나만 정적 필드가 할당됨
-클래스명.정적필드명으로 사용
-클래스 객체의 개수를 카운트하거나 유틸리티 값들을 저장하는 경우 사용함

Instance Field
-객체의 현재 상태를 저장할 수 있는 자료
-객체가 생성될 시 메모리 공간을 할당
-객체명.객체필드명으로 사용


class ValueClass
{
    private int value = 0; // 인스턴스 필드
    public static int count = 0; // 정적 필드
    public ValueClass() { count++; }
    public void setValue(int value) { this.value = value; } // 인스턴스 메소드
    public int getValue() { return this.value; } // 인스턴스 메소드
    public void print() { Console.WriteLine(“value={0}”, this.value); } // 인스턴스 메소드
    public static void printString(string str) { Console.WriteLine(str); } // 정적 메소드
    public static int getCount() { return count; } // 정적 메소드
}

class Program
{
    static void main(string[] args)
    {
        ValueClass c1 = new ValueClass();
        c1.setValue(10); // 인스턴스 메소드
        c1.print(); // 인스턴스 메소드 value=10
        ValueClass.printString(“test”); // 정적 메소드 (클래스명.정적메소드명) test
        ValueClass c2 = new ValueClass();
        c2.setValue(20); // 인스턴스 메소드
        c2.print(); // 인스턴스 메소드 value=20
        Console.WriteLine(“number of ValueClass: {0}”, ValueClass.getCount()); // 정적 메소드 (클래스명.정적메소드명) number of ValueClass: 2
       
Console.WriteLine(“number of ValueClass: {0}”, ++ValueClass.count); // 정적 필드 (클래스명.정적필드명) number of ValueClass: 3
    }
}

const vs readonly Field

const 상수(constant)은 컴파일타임(compile-time) 상수이다.
readonly 상수(constant)은 런타임(run-time) 상수이다.



// const
public const int Millennium = 2000;
public const double PI = 3.141592;

// readonly
public static readonly int ThisYear = 2010;
public class MyClass
{
    public readonly double PI;
    public MyClass()
    {
        PI = 3.141592;
    }
}

const 상수는 선언하는 순간부터 static 된다.
const 상수를 선언함과 동시에 초기화를 해주어야 한다.
const 상수는 컴파일시 값이 결정 되어져 있어야 한다.

readonly 상수는 static 키워드를 사용하면 static 상수가 된다. 사용하지 않으면 일반상수가 된다.
readonly 상수는 const 키워드를 사용하는 것처럼 반드시 초기화 필요없.
readonly 상수는 생성자를 통해서 런타임시 값이 결정될 있다.
한번 값이 결정되면 다시는 값을 변경할 수는 없다.

class

protected 접근자
-protected 접근 지정자를 사용한 멤버 필드와 메소드는 파생 클래스에서는 사용가능하나 클래스 외부에서는 호출하지 못함


static 필드와 메소드
-static field는 전역 데이터로 클래스당 하나만 할당됨
-클래스명.정적필드명 형태로 사용
-static method는 class method나 static member field 조작을 위한 메소드
-static method는 instance field는 접근 불가능

constructor (생성자)
-default constructor (기본 생성자)
-constructor overloading (생성자 오버로딩) 생성자를 여러 가지 형태로 정의
-constructor initializer (생성자 초기화 목록) 생성자들 사이의 정의가 비슷한 경우 코드를 간략하게 만들기 위해 사용

-private constructor (private 생성자) 정적 멤버만 포함하는 클래스에서 사용하며 클래스가 인스턴스화 될 수 없음을 분명히 하기 위해 private 접근 지정자를 사용
-static constructor (static 생성자) 정적 데이터 멤버를 초기화하는데 사용

destructor (소멸자)
-객체가 소멸될 때 필요한 정리 작업을 정의하는 부분    

Just another Kyoung Shin Park’s Lectures Sites site