컬렉션 식을 사용하여 공통 컬렉션 값을 만들 수 있습니다.
컬렉션 식은 평가 시 다양한 컬렉션 형식에 할당될 수 있는 간결한 구문입니다. 컬렉션 식에는 [과 ] 대괄호 사이에 일련의 요소가 포함되어 있습니다. 다음 예에서는 System.Span<T> 요소의 string를 선언하고 요일로 초기화합니다.
Span<string> weekDays = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
foreach (var day in weekDays)
{
Console.WriteLine(day);
}
컬렉션 식은 다양한 컬렉션 형식으로 변환될 수 있습니다. 첫 번째 예에서는 컬렉션 식을 사용하여 변수를 초기화하는 방법을 보여 주었습니다. 다음 코드는 컬렉션 식을 사용할 수 있는 다른 여러 위치를 보여 줍니다.
// Initialize private field:
private static readonly ImmutableArray<string> _months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
// property with expression body:
public IEnumerable<int> MaxDays =>
[31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
public int Sum(IEnumerable<int> values) =>
values.Sum();
public void Example()
{
// As a parameter:
int sum = Sum([1, 2, 3, 4, 5]);
}
상수 초기화와 같이 컴파일 시간 상수가 필요한 경우 또는 메서드 인수의 기본값으로 컬렉션 식을 사용할 수 없습니다.
이전 예에서는 모두 컬렉션 식의 요소로 상수가 사용되었습니다. 다음 예와 같이 요소에 대한 변수를 사용할 수도 있습니다.
string hydrogen = "H";
string helium = "He";
string lithium = "Li";
string beryllium = "Be";
string boron = "B";
string carbon = "C";
string nitrogen = "N";
string oxygen = "O";
string fluorine = "F";
string neon = "Ne";
string[] elements = [hydrogen, helium, lithium, beryllium, boron, carbon, nitrogen, oxygen, fluorine, neon];
foreach (var element in elements)
{
Console.WriteLine(element);
}
spread 요소
컬렉션 식의 컬렉션 값을 인라인하려면 spread 요소..를 사용합니다. 다음 예에서는 모음 컬렉션, 자음 컬렉션 및 문자 "y"를 결합하여 전체 알파벳에 대한 컬렉션을 만듭니다. 이는 다음 중 하나일 수 있습니다.
string[] vowels = ["a", "e", "i", "o", "u"];
string[] consonants = ["b", "c", "d", "f", "g", "h", "j", "k", "l", "m",
"n", "p", "q", "r", "s", "t", "v", "w", "x", "z"];
string[] alphabet = [.. vowels, .. consonants, "y"];
spread 요소 ..vowels는 평가 시 5개의 요소("a", "e", "i", "o" 및 "u")를 생성합니다. spread 요소 ..consonants는 consonants 배열의 숫자인 20개의 요소를 생성합니다. spread 요소의 변수는 foreach 문을 사용하여 열거 가능해야 합니다. 이전 예에 표시된 것처럼 spread 요소를 컬렉션 식의 개별 요소와 결합할 수 있습니다.
변환
컬렉션 식은 다음을 포함한 다양한 컬렉션 형식으로 변환될 수 있습니다.
- System.Span<T> 및 System.ReadOnlySpan<T>.
-
배열(예:
int[]또는string[]. - 컬렉션 식 형식에서 로 암시적으로 변환되는 매개 변수 형식이
ReadOnlySpan<T>인T메서드가 있는 모든 형식입니다. -
와 같은 System.Collections.Generic.List<T>을 지원하는 모든 형식입니다. 일반적으로 이 요구 사항은 해당 형식이 System.Collections.Generic.IEnumerable<T>를 지원하고 컬렉션에 항목을 추가하기 위한 액세스 가능한
Add메서드가 있음을 의미합니다. 컬렉션 식 요소 형식에서 컬렉션 요소 형식으로의 암시적 변환이 있어야 합니다. spread 요소의 경우 spread 요소 형식에서 컬렉션 요소 형식으로의 암시적 변환이 있어야 합니다. - 다음 인터페이스 중 하나:
비고
컬렉션 식을 사용하여 인라인 배열을 초기화할 수 없습니다. 인라인 배열에는 다른 초기화 구문이 필요합니다.
Important
컬렉션 식은 변환의 대상 형식에 관계없이 컬렉션 식의 모든 요소를 포함하는 컬렉션을 항상 만듭니다. 예를 들어 변환 대상이 System.Collections.Generic.IEnumerable<T>인 경우, 생성된 코드는 컬렉션 식을 평가하고 결과를 메모리 내 컬렉션에 저장합니다.
이 동작은 시퀀스가 열거될 때까지 인스턴스화되지 않을 수 있는 LINQ와 다릅니다. 컬렉션 식을 사용하여 열거되지 않는 무한 시퀀스를 생성할 수 없습니다.
컴파일러는 정적 분석을 사용하여 컬렉션 식으로 선언된 컬렉션을 만드는 가장 성능이 좋은 방법을 결정합니다. 예를 들어 빈 컬렉션 식 []은 초기화 후 대상이 수정되지 않는 경우 Array.Empty<T>()로 구현될 수 있습니다. 대상이 System.Span<T> 또는 System.ReadOnlySpan<T>인 경우 스토리지가 스택 할당될 수 있습니다.
컬렉션 식 기능 사양은 컴파일러가 따라야 하는 규칙을 지정합니다.
많은 API는 여러 컬렉션 형식을 매개 변수로 사용하여 오버로드됩니다. 컬렉션 식은 다양한 식 형식으로 변환될 수 있으므로 이러한 API에서는 올바른 변환을 지정하기 위해 컬렉션 식에 대한 캐스팅이 필요할 수 있습니다. 다음 변환 규칙은 일부 모호성을 해결합니다.
- 더 나은 컬렉션 형식 변환보다 더 나은 요소 변환이 선호됩니다. 즉, 컬렉션 식의 요소 형식은 컬렉션 형식보다 중요도가 높습니다. 이러한 규칙은 컬렉션 식에서 더 나은 변환을 위해 기능 사양에 설명되어 있습니다.
-
Span<T>, ReadOnlySpan<T> 또는 다른
ref struct형식으로 변환하는 것이 참조가 아닌 구조체 형식으로 변환하는 것보다 낫습니다. - 인터페이스가 아닌 형식으로 변환하는 것이 인터페이스 형식으로 변환하는 것보다 낫습니다.
컬렉션 식이 Span 또는 ReadOnlySpan으로 변환되면 범위 개체의 안전한 컨텍스트는 범위에 포함된 모든 요소의 안전한 컨텍스트에서 가져옵니다. 자세한 규칙은 컬렉션 식 사양을 참조하세요.
컬렉션 작성기
컬렉션 식은 잘 작동하는 모든 컬렉션 형식에서 작동합니다. 잘 동작하는 컬렉션에는 다음과 같은 특징이 있습니다.
-
Count컬렉션의 값Length또는 은(는) 열거될 때 요소 수와 동일한 값을 생성합니다. - System.Collections.Generic 네임스페이스의 형식은 부작용이 없는 것으로 추정됩니다. 따라서 컴파일러는 이러한 형식을 중간 값으로 사용할 수 있지만 그렇지 않으면 노출되지 않는 시나리오를 최적화할 수 있습니다.
- 컬렉션에서 적용 가능한
.AddRange(x)멤버를 호출하면x을(를) 반복하고 열거 된 모든 값을.Add(으)로 컬렉션에 개별적으로 추가하는 것과 동일한 최종 값이 생성됩니다.
.NET 런타임의 모든 컬렉션 형식은 잘 동작합니다.
Warning
사용자 지정 컬렉션 형식이 잘 동작하지 않으면 컬렉션 식과 함께 해당 컬렉션 형식을 사용할 때의 동작은 정의되지 않습니다.
형식은 Create() 메서드를 빌드하고 컬렉션 형식에 System.Runtime.CompilerServices.CollectionBuilderAttribute를 적용하여 작성기 메서드를 나타냄으로써 컬렉션 식 지원을 선택합니다. 예를 들어, 80자의 고정 길이 버퍼를 사용하는 애플리케이션을 생각해 보세요. 해당 클래스는 다음 코드와 유사할 수 있습니다.
public class LineBuffer : IEnumerable<char>
{
private readonly char[] _buffer;
private readonly int _count;
public LineBuffer(ReadOnlySpan<char> buffer)
{
_buffer = new char[buffer.Length];
_count = buffer.Length;
for (int i = 0; i < _count; i++)
{
_buffer[i] = buffer[i];
}
}
public int Count => _count;
public char this[int index]
{
get
{
if (index >= _count)
throw new IndexOutOfRangeException();
return _buffer[index];
}
}
public IEnumerator<char> GetEnumerator()
{
for (int i = 0; i < _count; i++)
{
yield return _buffer[i];
}
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
// etc
}
다음 샘플과 같이 컬렉션 식과 함께 사용하려고 합니다.
LineBuffer line = ['H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!'];
LineBuffer 형식은 IEnumerable<char>를 구현하므로 컴파일러는 이를 char 항목의 컬렉션으로 인식합니다. 구현된 System.Collections.Generic.IEnumerable<T> 인터페이스의 형식 매개 변수는 요소 형식을 나타냅니다.
LineBuffer 개체에 컬렉션 식을 할당하려면 애플리케이션에 두 가지 항목을 추가해야 합니다. 먼저, Create 메서드를 포함하는 클래스를 만들어야 합니다.
internal static class LineBufferBuilder
{
internal static LineBuffer Create(ReadOnlySpan<char> values) => new LineBuffer(values);
}
Create 메서드는 LineBuffer 개체를 반환해야 하며 ReadOnlySpan<char> 형식의 단일 매개 변수를 사용해야 합니다.
ReadOnlySpan의 형식 매개 변수는 컬렉션의 요소 형식과 일치해야 합니다. 제네릭 컬렉션을 반환하는 작성기 메서드는 제네릭 ReadOnlySpan<T>를 매개 변수로 갖습니다. 메서드는 액세스 가능하고 static이어야 합니다.
마지막으로 CollectionBuilderAttribute 클래스 선언에 LineBuffer를 추가해야 합니다.
[CollectionBuilder(typeof(LineBufferBuilder), "Create")]
첫 번째 매개 변수는 Builder 클래스의 이름을 제공합니다. 두 번째 특성은 작성기 메서드의 이름을 제공합니다.
.NET