출처 : https://code-maze.com/csharp-immutable-collections/
mutable과 immutable은 can change, cannot change의 뜻을 각각 가진다. 이 의미는 C#에서도 동일하다.
mutable object 값을 변경할 때, 값은 같은 메모리에서 변경된다. 하지만 immutable type은 새로운 memory가 생성되며 변경된 값을 저장한다.
- String : immutable
existing string 값을 변경하면, 새로운 object가 생성되고 기존 object는 참조하지 않는다. 따라서 지속적으로 값을 변경할 경우, unreferenced object 값이 늘어나고 garbage collector가 동작할때까지 application performance는 감소하게 된다. 이런경우는 mutable type을 사용하는 것이 좋다.
- StringBuilder : mutable
collections의 불변성을 보장받고 싶은 경우가 있다. C#에는 이런 경우를 위한, Immutable Collections을 제공한다.
Defining Immutability
immutable object는 값을 초기화한 이후, 변경할 수 없는 object이다.
불변성은 가독성과, 유지보수를 위해 필요하다. 우리는 어떠한 전역 변수나 공유상태를 변경하지 않는 함수를 고려할 수도 있고, 상태변수를 immutable하도록 만듦으로 2개의 쓰레드가 동시에 상태값을 변경하는 것을 막을 수 있다.
Different Immutable Collections in C#
immutable collection은 생성된 이후로는 변경되지 않는 구조를 갖는다. API가 regular collections이 제공하는 모든 동작을 허용하는 경우에도 완벽한 불변성을 갖는다. immutable collection의 변경은 스스로 변경하는 것이 아닌, 업데이트 상태를 갖는 새로운 immutable collection을 반환한다.
using System.Collections.Immutable;
var initialList = ImmutableList.Create<int>();
var updatedList = initialList.Add(1);
regular list처럼 ImmutableList도 Add 함수를 제공한다 하지만 처음 list에 추가하는 것이 아닌, 추가된 element와 함께 새로운 list를 생성한다.
Immutable Stack
public constructor가 없다. instance를 생성하기 위해서 factory methods를 호출한다.
var stack1 = ImmutableStack.Create<int>();
var stack2 = stack1.Push(1);
var stack3 = stack2.Push(2);
Assert.Equal(1, stack2.Peek());
var stack4 = stack3.Push(4);
var stack5 = stack4.Pop();
Assert.Equal(4, stack4.Peek());
Assert.Equal(2, stack5.Peek());
ImmutableStack<T> 는 2개의 stack 함수(Push, Pop)를 갖는다.
Immutable List
stack는 아주 단순한 데이터 구조이며 push, pop만 할 수 있다. list는 더 많은 함수를 갖고 있다.
var list1 = ImmutableList.Create<int>();
Assert.Empty(list1);
var list2 = list1.Add(1);
Assert.Single(list2);
var list3 = list2.Add(2);
Assert.Equal(2, list3.Count);
var list4 = list3.Add(3);
Assert.Equal(3, list4.Count);
var list5 = list4.Replace(2, 4);
Assert.Equal(3, list5.Count);
Immutable Array
BinarySearch 함수로 index를 통해 element에 접근할 수 있다. regular array는 고정된 길이를 제공하지만, Immutable Array는 더 나아가 elements가 변경되는 것을 막는다.
var immutableArray = ImmutableArray.Create<int>(1, 2, 3, 4);
var firstElement = immutableArray[0];
Assert.Equal(1, firstElement);
var lastElementIndex = immutableArray.BinarySearch(4);
Assert.Equal(3, lastElementIndex);
일반적으로 쓰는 것보다 읽는 것이 빈번할 떄 ImmutableArray<T>를 사용한다.
Immutable Dictionary
var dict1 = ImmutableDictionary.Create<int, char>();
var dict2 = dict1.Add(1, 'a');
Assert.Single(dict2);
Assert.True(dict2.ContainsKey(1));
Assert.Equal('a', dict2[1]);
var dict3 = dict2.Add(2, 'b');
Assert.Equal(2, dict3.Count);
var dict4 = dict3.Remove(2);
Assert.Single(dict4);
ContainsKey()함수로 키의 존재여부를 체크할 수 있다.
사용성을 위해서 immutable collections도 IList, ICollection, IEnumerable, IDictionary와 같은 interface를 구현하지만, 이러한 interface의 mutating methods의 구현은 NotSupportedException을 throw한다.
Immutable SortedSet
정렬되어있고, 중복되지 않는다.
var sortedSet1 = ImmutableSortedSet<int>.Empty;
var sortedSet2 = sortedSet1.Add(5);
var sortedSet3 = sortedSet2.Add(1);
Assert.Equal(1, sortedSet3[0]);
Assert.Equal(5, sortedSet3[1]);
var sortedSet4 = sortedSet2.Add(1);
Assert.Equal(2, sortedSet4.Count);
var sortedSet5 = sortedSet4.Remove(1);
Assert.Single(sortedSet5);
'C#' 카테고리의 다른 글
C#] Method Parameters - parameters 전달 (0) | 2023.08.22 |
---|---|
C#] type, System.Type, System.Reflection (0) | 2023.06.19 |
C#] Asynchronous VS Multithreading (0) | 2023.04.25 |
C#] 특수문자 (주석, $, @) (0) | 2023.03.21 |
.NET] DTO vs POCO 차이점 (0) | 2023.02.09 |
댓글