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

public abstract class Shape
{
protected Shape(string name) { this.name = name; }
private string name;
public virtual void Print() { Console.Write(this.name); }
}
public class Triangle: Shape
{
public Triangle(string name): base(name) { this.bottom = 1; this.height = 1 }
private double bottom, height;
public override void Print()
{
base.Print();
Console.WriteLine(” 밑변: {0} 높이: {1}”, this.bottom, this.height);
}
}
public class Rectangle: Shape
{
public Rectangle(string name): base(name) { this.width = 2; this.height = 3 }
private double width, height;
public override void Print()
{
base.Print();
Console.WriteLine(” 가로: {0} 세로: {1}”, this.width, this.height);
}
}
class ShapeTest
{
static void Main()
{
// Shape s = new Shape(“도형”); // Error CS0144, Cannot create an instance of the abstract class
Shape s = new Triangle(“삼각형”);
s.Print(); // 삼각형 밑변: 1 높이: 1
s = new Rectangle(“직사각형”);
s.Print(); // 직사각형 가로: 2 세로: 3
}
}

 

 

new vs virtual 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에 의해서 Derived 의 Print 메소드 호출)
}
}

Protected

public 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
public void Move()
{
if (disel)
Console.Write(“Car 디젤”);
else
Console.Write(“바퀴 {0} 자동차가 굴러간다.”, wheel);
}

}

public 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()
{

// base의 gasoline과 this의 gasoline을 구분해야하는 경우
if (base.gasoline)
Console.Write(“Car가솔린”);
if (this.gasoline)
Console.Write(“Sedan 가솔린”);

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; // instance field
string name; // instace field
static double interest; // static field

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

public BankAccount(double balance, string name) // constructor
{

this.balance = balance;
this.name = name;
BankAccount.interest = 0.7; // 0.7%

}

public void Deposit(double amount) // instance method
{

balance += amount;

}

public void Withdrawal(double amount) // instance method
{

balance -= amount;

}

public void Print() // instance method
{

double currentBalance = balance + balance * BankAccount.interest * 0.01;

Console.WriteLine(“{0}의 계좌 잔고는 {1}”, name, currentBalance);

}

public static void SetInterestRate(double interest) // static method
{

BankAccount.interest = interest;

}

}

 

class Program
{

static void Main(string[] args)
{

BankAccount b = new BankAccount(5000, “HCI222222222222”);
b.Print();

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

b.Withdrawal(500);
b.Print();

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

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

}

}

Class

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

static 필드와 메소드
-static field는 전역 데이터로 클래스당 하나만 할당됨
-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 (소멸자)
-객체가 소멸될 때 필요한 정리 작업을 정의하는 부분

C# Internal Class vs Public Class

class Test { // internal class Test (현재의 어셈블리 내부에서 접근가능한 클래스)
        //code inside it
}

public class Test{ (다른 어셈블리에서도 접근가능한 클래스)
       //code inside it
}

internal(C# 참조)
http://msdn.microsoft.com/ko-kr/library/7c5ka91b.aspx

class vs public class
http://stackoverflow.com/questions/12392876/class-vs-public-class

const vs readonly Field

<strong><em><span style=”color: #0000ff;”>const 상수(constant)은 컴파일타임(compile-time) 상수이다.</span></em>
<span style=”color: #008000;”>readonly 상수(constant)은 런타임(run-time) 상수이다.</span></strong>
<div>// const
public <strong><span style=”color: #0000ff;”>const</span></strong> int Millennium = 2000;
public <strong><span style=”color: #0000ff;”>const</span></strong> double PI = 3.141592;// readonly
public static <strong><span style=”color: #008000;”>readonly</span></strong> int ThisYear = 2010;</div>
<div></div>
<div>public class MyClass
{</div>
<div style=”padding-left: 30px;”>public <strong><span style=”color: #008000;”>readonly</span></strong> double PI;
public MyClass()
{
PI = 3.141592;
}</div>
<div>}</div>
&nbsp;

<span lang=”EN-US” xml:lang=”EN-US”>const</span> 상수는 선언하는 순간부터 <span lang=”EN-US” xml:lang=”EN-US”>static</span>이 된다<span lang=”EN-US” xml:lang=”EN-US”>.
const 상수를 선언함과 동시에 초기화를 해주어야 한다.
const 상수는 컴파일시 값이 결정 되어져 있어야 한다.</span>

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

Local Variable vs Field vs Method

Local variables in C# must be initialized before they are used.

https://msdn.microsoft.com/en-us/library/vstudio/s1ax56ch(v=vs.100).aspx

class Test
{

     static int test1; // static field test1 = 0 Warning CS0414: The field ‘Test.test1’ is assigned but its value is never used

    int test2; // instance field test2 = 0 Warning CS0649: The field ‘Test.test2’ is never assigned to, and will always have its default value 0

     public void Foo() // instance method
{

          int test3;                 // Declaration only; Not initialized warning CS0168: The variable ‘test3’ is declared but never used

int test4 = test2;         // Ok
          //int test5 = test3;         // Error CS0165: Use of unassigned local variable ‘test3’

}

     public static void Foo2() // static method
    {

        test1 = 2;

    }

}

class Program
{

static void Main(string[] args)
{

            // Declaration only
            float temperature; // warning CS0168: The variable ‘temperature’ is declared but never used
            string name; // warning CS0168: The variable ‘name’ is declared but never used
            Test myClass; // The variable ‘myClass’ is declared but never used

            // Declaration with initializers 
            double limit = 3.5;
            int[] source = { 0, 1, 2, 3, 4, 5 };
            var query = from item in source
                        where item <= limit
                        select item;

            Test.Foo2(); // Static method
           // Test.Foo();  // Error CS0120: An object reference is required for the non-static field, method, or property 

}

}