C# 13 - (4) Indexer를 이용한 개체 초기화 구문에서 System.Index 연산자 허용
개인적으로는 한 번도 써보려고 시도조차 하지 않았던 구문에 대한 지원이 추가됐습니다. ^^
Implicit index access
; https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-13#implicit-index-access
Support implicit indexer access in object initializers #70649
; https://github.com/dotnet/roslyn/pull/70649
예를 들어, 사용자 타입 내에 확정된 배열을 가진 멤버가 있는 경우,
public class MyFixedArrayType
{
public int[] Numbers = new int[5];
}
이것을 초기화할 때 (
C# 8에 추가한) 범위 연산자 중 하나인 "^" (System.Index) 연산자를 사용할 수 있게 됐습니다.
MyFixedArrayType m = new MyFixedArrayType()
{
Numbers = {
[^1] = 0,
[^2] = 1,
[^3] = 2,
[^4] = 3,
[^5] = 4,
} // Numbers = { 4, 3, 2, 1, 0 }
};
물론, 표현할 수 있게 되었으니 긍정적일 수는 있으나 사실 그다지 자주 쓰일만한 구문은 아닙니다. 가령, 위의 코드를 타입 수준에서 배열 멤버의 길이를 미리 지정하지 않는다면,
public class MyArrayType
{
public int[]? Numbers;
}
이를 초기화할 때는 ^ 연산자를 사용할 수 없습니다. (컴파일 오류가 발생합니다.)
MyArrayType m = new MyArrayType()
{
Numbers = new int[5] {
[^1] = 0, // error CS0131: The left-hand side of an assignment must be a variable, property or indexer
}
};
또한, List 타입인 경우라면 컴파일까지는 가능하지만,
List<int> m = new List<int>(5) // 5개의 공간을 확보했지만,
{
[^1] = 0,
};
(공간을 확보했음에도) 실행 시 System.ArgumentOutOfRangeException 예외가 발생합니다.
System.ArgumentOutOfRangeException: 'Index was out of range. Must be non-negative and less than the size of the collection. (Parameter 'index')'
왜냐하면, C# 컴파일러는 위의 코드를 다음과 같이 해석하기 때문에,
List<int> list = new List<int>(5);
int num = list.Count - 1; // Capacity가 아닌 Count를 사용하기 때문에,
// num == -1이 되고,
list[num] = 0; // 이 코드에서 음수 인덱스를 사용하는 결과가 돼 예외 발생
오류가 발생하는 것이 당연합니다. 그래도 그나마 현실적인 사용 예가 다음의 이슈에 나오는데요,
Implicit index indexer doesn't work in object initializer #67533
; https://github.com/dotnet/roslyn/issues/67533
위의 이슈에 있는 코드는 타입 내에 indexer 멤버를 정의하고 있어 동적인 배열 정의가 가능합니다. 즉, 다음과 같은 식으로 감싸서 제공할 수 있는데요,
public class MyIndxerType
{
char[] _nubmers;
public MyIndxerType(int count)
{
_nubmers = new char[count];
}
public int Count => _nubmers.Length;
public char this[int index]
{
get => _nubmers[index];
set => _nubmers[index] = value;
}
}
이런 경우, ^ 연산자를 사용해 자연스럽게 초기화할 수 있습니다.
MyIndxerType m = new MyIndxerType(10)
{
[^1] = '\0'
};
가장 마지막 글자에 '\0'을 넣어주는 코드인데요, 만약 인덱스 연산자를 사용하지 못한다면 아래와 같이 별도로 초기화하는 구문을 추가해야 합니다.
MyIndxerType m = new MyIndxerType(10);
m[m.Length - 1] = '\0'; // C# 12 이하에선 이렇게 나눠서 초기화
// 또는,
m[^1] = '\0';
저런 경우라면, 편할 수 있겠다는 수긍은 가지만... ^^; 과연 저런 코드로 사용 빈도까지 고려한다면 그냥 잊고 살아도 좋을 신규 문법인 듯합니다. (혹시 이 글을 읽어보시는 분 중에, 저 기능이 아쉬웠던 분이 계셨다면 덧글 부탁드립니다. )
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]