[C#] 구조체의 get/set을 조심하자
잠깐 생각해보면 당연하고 별 거 아닌데, 아무 생각 없이 쓰다가 디버깅때문에 고통받았다.
보통 외부에서 참조는 할 수 있지만 내부에서만 변경하고 싶은 객체를 만들 때, get/set을 쓰는 게 일반적이다.
예시로 단순히 int 변수를 가진 somethingClass 객체를 만든다고 해 보자.
public static somethingClass A { get; private set; }
public static void Main(string[] args)
{
A = new somethingClass(0);
A.count++;
Console.WriteLine(A.count);
//Output is 1
}
public class somethingClass
{
public int count;
public somethingClass(int count)
{
this.count = count;
}
}
자... 그런데 모종의 사유로 이 somethingClass를 struct 타입으로 바꿔야 한다고 해 보자.
디폴트 생성자 이슈도 체크했고, 관련된 메서드도 체크했고, 그러니까 문제 없이 잘 돌아가겠지?
public static somethingStruct A { get; private set; }
public static void Main(string[] args)
{
A = new somethingStruct(0);
A.count++;
Console.WriteLine(A.count);
//Output is 0
}
public struct somethingStruct
{
public int count;
public somethingStruct(int count)
{
this.count = count;
}
}
와! count의 output이 class 타입과 달리 0이다! 크아악!
왜 0인데요
struct 타입은 값 형식이고, get/set은 메서드 본문과 유사한 방식으로 작동한다.
A = new somethingStruct(0); //A에 새 객체를 만들어서 넣음
A.count++; //그런데 A를 get해서 **그 객체**의 count를 증가시킴
Console.WriteLine(A.count); //A의 count를 출력함. 0임.
//Output is 0
천천히 살펴보자.
우선 A에 새 somethingStruct를 넣었다. 그거야 뭐, 정상 작동한다.
그리고 A.count++;는 다음과 같은 동작을 거친다.
1) 'A'의 복사본을 생성한다. 설명하기 쉽게 'A2'라고 명명하겠다.
2) 복사본인 'A2'의 count가 1 증가된다.
3) A.count를 출력해봤자 'A'를 참조하지, 'A2'를 참조하지 않는다.
결국은 참조 타입과 값 타입의 차이인데, get/set을 쓰다 보니 놓친 것 뿐이다.
public static somethingStruct GetA() => A;
이 메서드를 작동시킨다면 A는 값 타입이므로 복사되어 반환될 것이다. get도 똑같이 동작한다.
그러니 get을 사용한 A.count++;는 A 복사본의 count를 증가시킬 것이다. 원본에는 영향을 미치지 않는다.
오, 그렇구나~ 당연한 것인데 헷갈린 것 뿐이구나~
앞으로는 조심하면 되겠다.
그런데 이 글을 쓰다가 정말 별개로 재미있는... 아니... 재미 없을지도 모르는 사실을 발견했다.
자... 아래는 오류가 안 나는데...
A = new somethingStruct(0);
A.count++;
이건 오류 남.
A = new somethingStruct(0);
A.count = A.count + 1;
//Main.cs(11,15): error CS1612: Cannot modify a value type return value of `MyCompiler.Program.A'. Consider storing the value in a temporary variable
황당해서 GPT한테 물어봤음.
보통은 스택오버플로우를 다 뒤져서라도 알아내는데,
이번 건 킹받아서 그냥 묻어두기로 했다. ^O^
'프로그래밍 > C#' 카테고리의 다른 글
왜 partial Enum은 없는 걸까? (0) | 2024.03.21 |
---|---|
ZString 라이브러리는 어떻게 제로 할당을 주장하는가 (0) | 2023.08.04 |
C# 9.0 새 기능 알아보기 (0) | 2023.01.16 |
C# 8.0 새 기능 알아보기 (0) | 2022.09.20 |
C# 구조체 : 기본 매개변수를 사용한 생성자는 호출되지 않을 수도 있다 (0) | 2022.07.10 |
댓글
이 글 공유하기
다른 글
-
왜 partial Enum은 없는 걸까?
왜 partial Enum은 없는 걸까?
2024.03.21 -
ZString 라이브러리는 어떻게 제로 할당을 주장하는가
ZString 라이브러리는 어떻게 제로 할당을 주장하는가
2023.08.04 -
C# 9.0 새 기능 알아보기
C# 9.0 새 기능 알아보기
2023.01.16 -
C# 8.0 새 기능 알아보기
C# 8.0 새 기능 알아보기
2022.09.20