C# 13: ref struct 타입에 대한 기능 향상
C# 13에서부터 async 메서드 안에서 ref 로컬이나 ref struct 로컬 선언이 가능해졌다.
단, await 또는 yield 경계를 넘어서 엑세스하면, 컴파일러가 메모리 안전성을 위해 오류를 발생시킨다.
아래 예제의 MyAsync 메서드에서는 정수형의 ReadOnlySpan변수 span이 ref struct 로컬 변수로 선언되어 있다.
span을 await 이전에 사용하면 문제가 없으나, ErrorAsync 메서드에서 처럼 await 이후에 사용하면 컴파일러가 오류를 발생한다.
예제
public static void Main()
{
MyAsync(new int[] { 1, 2, 3 }).Wait();
}
static async Task<int> MyAsync(ReadOnlyMemory<int> mem)
{
ReadOnlySpan<int> span = mem.Span; // ref struct 로컬
int first = span[0];
await Task.Delay(1);
return first;
}
/* ERROR
static async Task<int> ErrorAsync(ReadOnlyMemory<int> mem)
{
ReadOnlySpan<int> span = mem.Span; // ref struct 로컬
int first = span[0];
await Task.Delay(1);
// span을 여기서 다시 쓰면(경계 넘어) 컴파일러가 에러 발생
// CS4007 Error: Instance of type 'System.ReadOnlySpan<int>' cannot be preserved across 'await' or 'yield' boundary.
int res = span[0];
return res;
} */
제네릭에서 ref struct 타입 인자 허용
C# 13에서 제네릭 타입(혹은 메서드)의 타입 파라미터에 anti-constraint 인 allows ref struct를 붙이면,
ref struct를 타입 파라미터로 받을 수 있게 되었다.
아래 예제에서 Box 클래스는 T 타입 파라미터에 allows ref struct 제약 조건이 붙어서, ReadOnlySpan<char> 등과 같은
ref struct 타입을 타입 파라미터로 받을 수 있다. ref struct 타입은 스택에만 존재해야 하는 타입인데,
이걸 잘못해서 힙으로 흘려보내면 (예: 필드로 저장, 리턴으로 반환, async 캡처) 메모리 안전 문제가 발생한다.
이에 scoped 라는 C# 11 키워드를 붙여 ref struct 타입을 그 메서드 안에서 사용하는 것을 명시하였다.
예제
// 제네릭 타입파라미터 T로 ref struct 타입도 허용하는 Box 클래스
public sealed class Box<T> where T : allows ref struct
{
// value는 ref struct 타입일 수 있으므로,
// scoped (C# 키워드)를 사용하여 이 메서드 안에서만
// 사용함을 컴파일러에게 명시함
public void Use(scoped T value)
{
if (value is ReadOnlySpan<char> span)
{
for (int i = 0; i < span.Length; i++)
{
Console.Write(span[i]);
}
}
}
}
본 웹사이트는 광고를 포함하고 있습니다. 광고 클릭에서 발생하는 수익금은 모두 웹사이트 서버의 유지 및 관리, 그리고 기술 콘텐츠 향상을 위해 쓰여집니다.