프로그래밍/C#

[C#] 구조체의 get/set을 조심하자

Doublsb 2024. 6. 4. 11:52

잠깐 생각해보면 당연하고 별 거 아닌데, 아무 생각 없이 쓰다가 디버깅때문에 고통받았다.
 
 
 
보통 외부에서 참조는 할 수 있지만 내부에서만 변경하고 싶은 객체를 만들 때, 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^

반응형