struct property

이번엔 간혹 놓칠때가 있는 기초적인 내용에 대해 적어 보겠습니다.

c#에서 struct를 property로 사용할 때 주의 해야할 점이 있습니다.

internal class Program
{
	static void Main(string[] args)
	{
		var test = new TestClass();
		test.Foo();
	}
}

public class TestClass
{
	public TestStruct Val1 { get; set; }
	public TestStruct Val2;
	private TestStruct _val;
	public TestStruct Val3
	{
		get { return _val; }
		set { _val = value; }
	}

	public void Foo()
	{
		Val1.SetValue();
		Console.WriteLine(Val1.Value);

		Val2.SetValue();
		Console.WriteLine(Val2.Value);

		Val3.SetValue();
		Console.WriteLine(Val3.Value);

		_val.SetValue();
		Console.WriteLine(Val3.Value);
	}
}

public struct TestStruct
{
	public int Value;
    public void SetValue()
	{
		Value = 10;
	}
}

위 소스를 실행 했을 때 결과가 예상 되시나요?

10

10

10

10

이 나올거 같지만

실제 결과는

0

10

0

10

이 나옵니다.

원인은 c# 에서 property의 get은

참조 타입의 경우 해당 참조를 그대로 전달 하지만

값 타입의 경우 복사본을 전달 하게 됩니다.

Val1.SetValue(); 의 경우

복사 된 임시 TestStruct 의 Value 를 10으로 설정 한것이기 때문에

실제 Val1의 Value는 변화가 없습니다.

하지만 set은 실제 property에 저장 되므로

헤깔리지 않도록 주의 해야 합니다.

11개의 좋아요

조금 다른 주제가 될 수도 있지만, 그렇기 때문에 값 타입값처럼 동작하도록 만들어야 한다고 생각합니다. 값처럼 동작한다는 것은 다르게 말하면 불변 객체(immutable object)여야 한다는 뜻입니다. 잘 생각해 보면 System.Int32, System.Char과 같은 타입들도 모두 값 타입인데 위와 같은 혼란을 겪지 않습니다. 왜 그럴까 생각해 보면 해당 타입들이 모두 불변이기 때문입니다.

객체가 불변이라는 것은 참조를 통해 전달되었든 사본을 통해 전달되었든 언제나 상태의 변화가 전파되지 않는다는 뜻이 됩니다. 당연합니다. 상태를 바꿀 수 없게 막아뒀기 때문에 상태의 변화가 전파될지를 걱정하지 않아도 되는 것입니다. 그래서 불변성(immutability)을 흔히 무상태성(statelessness)이라고 표현하기도 합니다. 불변 객체는 참조를 통해 전달되든 사본을 통해 전달되든 의미론의 변화가 없기 때문에 헷갈릴 일이 없는 것입니다.

C#에서는 구조체를 정의할 때 아예 이 타입이 불변성을 깨뜨리지 않도록 강제할 수단도 제공합니다. 바로 readonly struct 키워드를 쓰는 것입니다. 이렇게 하면 모든 필드를 readonly로 선언해야 하기 때문에 결과적으로 상태를 바꿀 수 없게 됩니다. 개인적으로는 성능을 위해 보이지 않는 캐시를 내부적으로 보존해야 한다거나 하는 특수한 상황이 아니면 구조체는 항상 readonly로만 선언하는 편입니다.

7개의 좋아요

vo(value object)에 적합하죠