참치김밥은 최고의 한식이다

[Effective C# 2판] Item 4 : 값 타입과 참조 타입을 구분하라 본문

책/C#

[Effective C# 2판] Item 4 : 값 타입과 참조 타입을 구분하라

l__j__h 2024. 2. 21. 13:08

구조체(값 타입)는 데이터를 저장하고, 클래스(참조 타입)는 동작을 정의한다.

 

첫 번째 비교

아래 코드는 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 인터페이스가 데이터 멤버 접근용 프로퍼티 뿐인가?

자식 클래스를 절대 갖지 않는다고 확신하는가?

다형성이 필요한 일은 없을 것으로 확신하는가?

 

이래도 쓰임새를 예상하기 어렵다면, 미래의 확장 가능성을 위해 우선 참조 타입을 사용하자.

728x90