[Effective C# 2판] Item 4 : 값 타입과 참조 타입을 구분하라
구조체(값 타입)는 데이터를 저장하고, 클래스(참조 타입)는 동작을 정의한다.
첫 번째 비교
아래 코드는 Employee가 Class가 될 때 문제가 생긴다.
public struct Employee{
public string Position {get; set;}
public decimal CurrentPayAmount {get; set;}
public void Pay(BankAccount b)
=> b.Balance += CurrentPayAmount;
}
Employee e1 = Employees.Find(e => e.Position == "CEO");
BankAccount CEOBankAccount = new BankAccount();
decimal Bonus = 10000;
e1.CurrentPayAmount += Bonus;
e1.Pay(CEOBankAccount);
Employee가 struct일 때 : 값타입일 때
e1.CurrentPayAmount += Bonus; 를 해도, e1은 값타입이기 때문에, Employees 배열 내에 있는 개체를 수정하는 것은 아니다. 즉, Employee e1 = Employees.Find(e => e.Position == "CEO"); 에서, e1은 구조체이며, e1을 수정한다고 해서 배열 Employees 내부의 개체에는 영향이 가지 않는다. 따라서, e1.CurrentPayAmount += Bonus;를 해도, 배열 Employees 내부의 원본 개체에는 영향이 가지 않으며, 이번 한 번만 Bonus만큼 봉급을 더 주고 싶을 때 유용하다.
Employee가 Class일 때 : 참조타입일 때
Employee e1 = Employees.Find(e => e.Position == "CEO"); 에서, e1은 클래스이며, e1을 수정하면 즉 e1이 참조 중인 Employees 내부의 원본 개체를 수정하는 것이 된다. 따라서, e1.CurrentPayAmount += Bonus;를 하면, 배열 Employees 내부의 원본 개체의 값을 수정하는 꼴이 된다. 따라서, 이번 한 번만 봉급을 올려주는 게 아니라, e1의 봉급이 아예 +Bonus만큼 수정되어, 계속 봉급을 더 주게 되는 것이 된다.
두 번째 비교
메모리 할당 횟수 비교
MyType[] arrayOfTypes = new MyType[100];
이라는 코드가 있을 때,
- MyType 이 struct(값 타입)인 경우 : MyType 크기의 100배에 해당하는 메모리 할당이 1번 일어난다.
- MyType이 class(참조 타입)인 경우 : MyType 크기의 100배에 해당하는 메모리 할당이 1번 +각각의 배열 요소가 참조할 개체 초기화 100번 = 101번
→ class일 때 힙이 조각나서 성능도 떨어지고, 시간도 오래 걸림. 하지만, 이러한 기준은 값 타입과 참조 타입을 선택할 때 가장 낮은 우선순위로, 가장 마지막에 고려해 봄직하다. 이보다는 타입의 용도(데이터 저장용? or 다양한 동작 처리용?)를 훨씬 중요하게 고려해야 한다.
만약 다음 질문에 대하여 모두 “예”라고 답할 수 있다면, 값 타입을 사용하는 것이 맞다.
◇ 주요 용도가 데이터 저장인가?
◇ 변경 불가능하게 만들 수 있는가? (원자성이 있는가?)
◇ 크기가 작을 것으로 기대되는가?
◇ public 인터페이스가 데이터 멤버 접근용 프로퍼티 뿐인가?
◇ 자식 클래스를 절대 갖지 않는다고 확신하는가?
◇ 다형성이 필요한 일은 없을 것으로 확신하는가?
이래도 쓰임새를 예상하기 어렵다면, 미래의 확장 가능성을 위해 우선 참조 타입을 사용하자.