C# 구조체 : 기본 매개변수를 사용한 생성자는 호출되지 않을 수도 있다
문제 상황
나는 여느 때처럼 클래스 객체를 사용해 다른 함수에게 데이터를 넘겨주고 있었다.
public class Tester : MonoBehaviour
{
private void Start()
{
var data = new Data();
Initialize(data);
}
public void Initialize(Data data)
{
//Something
}
}
public class Data
{
public int crushId = -1;
public int count = 0;
public Data(int crushId = -1, int count = 0)
{
this.crushId = crushId;
this.count = count;
}
}
그런데, 클래스 객체가 이곳저곳에 호출되면서 중간에 객체의 내용이 변경되어 전달되는 문제가 생겼다.
이를 해결하기 위해 클래스를 구조체로 변경하여 전달하기로 했다.
public struct Data
{
public int crushId;
public int count;
public Data(int crushId = -1, int count = 0)
{
this.crushId = crushId;
this.count = count;
}
}
그리고 평소처럼 파라미터 없이 구조체 객체를 만들어 전달했더니...
당당하게도 새로 만들어진 구조체 객체는 crushId로 0을 들고 있는 것이 아닌가!
디버깅을 해 보니 내가 만들어 놓은 생성자는 호출도 안 되고 있었다. 대체 어떻게 된 것이지?
private void Start()
{
var data = new Data();
print(data.crushId);
print(data.count);
}
이유
구조체가 값 형식이고, C#은 구조체의 자체적인 기본 생성자를 가지고 있기 때문에 생기는 오류다.
실제로, 아무 파라미터도 없는 생성자를 구조체에서 생성하려고 하면 다음과 같은 오류가 발생한다.
오류 CS0568 구조체는 매개 변수가 없는 명시적 생성자를 포함할 수 없습니다.
이 자체적인 기본 생성자는 구조체의 모든 필드 값을 기본값으로 설정하여 생성한다.
그러므로 int값의 필드는 모두 0이 되어 나왔던 것.
그렇다면 왜 구조체에서 파라미터 없는 생성자를 만들지 못하게 했을까?
스택 오버플로우에서 유저들이 토론하는 스레드를 발견할 수 있었다.
가장 추천 수가 많은 사람의 의견으로는, 값 형식인 구조체를 매번 생성자를 사용하여 초기화하는 것이 효율적이지 않다는 것이다.
MyStruct[] foo = new MyStruct[1000];
이 상황에서, 새롭게 생성되는 MyStruct 객체 1000개는 모두 생성자를 부르면서 생성되어야 하는가?
만약 MyStruct가 구조체가 아니라 클래스였다면, 저 1000개의 객체는 모두 Null이 될 것이라고 예상했을 것이다.
그러나 구조체는 참조 타입이 아니라 값 타입이므로 필드를 어떻게든 모두 만들어내야만 하므로, 기본 생성자가 없다면 비효율적인 상황이 만들어지게 될 것이다.
해결 방법
간단하다.
생성자를 이용해 구조체를 초기화하고 싶다면 파라미터 없이 부르지 말자.