Microsoft MVP성태의 닷넷 이야기
닷넷: 2346. C# 14 - (2) Span 타입과 배열 간의 암시적 형변환 [링크 복사], [링크+제목 복사],
조회: 2668
글쓴 사람
정성태 (seongtaejeong at gmail.com)
홈페이지
첨부 파일
(연관된 글이 1개 있습니다.)
(시리즈 글이 12개 있습니다.)
닷넷: 2342. C# 14 - (취소된 글)
; https://www.sysnet.pe.kr/2/0/13970

닷넷: 2343. C# 14 - (1) 속성 구문에서 문맥 키워드로 추가되는 field 예약어
; https://www.sysnet.pe.kr/2/0/13971

닷넷: 2346. C# 14 - (2) Span 타입과 배열 간의 암시적 형변환
; https://www.sysnet.pe.kr/2/0/13974

닷넷: 2347. C# 14 - (3) 형식 인자가 없는 제네릭 타입의 nameof 지원
; https://www.sysnet.pe.kr/2/0/13975

닷넷: 2349. C# 14 - (4) 문자열 리터럴을 utf-8 인코딩으로 저장
; https://www.sysnet.pe.kr/2/0/13977

닷넷: 2350. C# 14 - (5) 람다 매개 변수에 접근자가 있는 경우에도 타입 생략 가능
; https://www.sysnet.pe.kr/2/0/13986

닷넷: 2351. C# 14 - (6) event와 생성자에도 partial 메서드 적용
; https://www.sysnet.pe.kr/2/0/13987

닷넷: 2354. C# 14 - (7) 확장 메서드에 정적 메서드와 속성 지원을 위한 전용 구문 추가
; https://www.sysnet.pe.kr/2/0/13998

닷넷: 2355. C# 14 - (8) null 조건부 연산자 개선 - 대입문에도 사용 가능
; https://www.sysnet.pe.kr/2/0/13999

닷넷: 2357. C# 14 - (9) 새로운 지시자 추가 (Ignored directives)
; https://www.sysnet.pe.kr/2/0/14003

닷넷: 2359. C# 14 - (10) 복합 대입 연산자의 오버로드 지원
; https://www.sysnet.pe.kr/2/0/14008

닷넷: 2360. C# 14 - (11) Expression Tree에 선택적 인수와 명명된 인수 허용
; https://www.sysnet.pe.kr/2/0/14009




C# 14 - (2) Span 타입과 배열 간의 암시적 형변환

시리즈의 2번째는,

Working Set C#
; https://github.com/dotnet/roslyn/blob/main/docs/Language%20Feature%20Status.md#working-set-c

[Proposal]: First-Class Span Types #7905
; https://github.com/dotnet/csharplang/issues/7905

Implicit span conversions
; https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-14#implicit-span-conversions

Span 타입에 관한 내용입니다. C# 7.2와 함께 BCL에 도입된 Span은,

C# 7.2 - Span<T>
; https://www.sysnet.pe.kr/2/0/11534

관리 및 비관리 메모리에 대한 일관성 있는 참조를 제공하면서도 성능까지 높일 수 있게 해주는 타입입니다. 직관적으로는 배열과 유사하지만, 아쉽게도 그동안 별도의 Span<T> 타입으로만 제공되었기 때문에 사용하기가 다소 불편했던 점이 있습니다.

물론 C# 언어가 버전업을 하면서 그런 부분들이 점차로 개선되었고,

C# 11 - Span 타입에 대한 패턴 매칭 (Pattern matching on ReadOnlySpan<char>)
; https://www.sysnet.pe.kr/2/0/13113

C# 12 - 컬렉션 식(Collection Expressions)
; https://www.sysnet.pe.kr/2/0/13415

C# 13 - (5) params 인자 타입으로 컬렉션 허용
; https://www.sysnet.pe.kr/2/0/13705

C# 13 - (9) 메서드 바인딩의 우선순위를 지정하는 OverloadResolutionPriority 특성 도입 (Overload resolution priority)
; https://www.sysnet.pe.kr/2/0/13755

C# 14에 와서 다음의 5가지 규칙을 만족하게 되면서,

  1. T 타입의 1차원 배열을 Span<T>으로 암시적 형변환
  2. E 타입과 U 타입이 identity conversion 또는 공변일 때, E 타입의 1차원 배열을 ReadOnlySpan<U>으로 암시적 형변환
  3. E 타입과 U 타입이 identity conversion 또는 공변일 때, E 타입의 Span<E> 타입을 ReadOnlySpan<U> 타입으로 암시적 형변환
  4. E 타입이 U 타입에 대해 identity conversion 또는 공변일 때, ReadOnlySpan<E> 타입을 ReadOnlySpan<U> 타입으로 암시적 형변환
  5. string 타입을 System.ReadOnlySpan<char> 타입으로 암시적 형변환

사실상 언어 내에서 배열과 다름없는 대우를 받게 된 것입니다. 설명할 내용이 저게 전부이긴 한데... 이렇게만 설명하고 끝내면 섭섭할 테니 각각의 규칙에 해당하는 예를 들어 보겠습니다. ^^





1. T 타입의 1차원 배열을 Span<T> 타입으로 암시적 형변환

이 규칙은 C# 13 이전에도 지원했던 것으로, 다음과 같은 코드로 확인할 수 있습니다.

internal class Program
{
    static void Main(string[] args)
    {
        int[] arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
        PrintArray(arr); // 1차원 배열을 Span 타입에 전달 (암시적 형변환)
    }

    // int [] 배열도 전달 가능
    static void PrintArray(Span<int> span)
    {
        for (int i = 0; i < span.Length; i++)
        {
            Console.WriteLine(span[i]);
        }
    }
}

뭐, 특별한 것이 없으니 이 정도로 넘어갑니다. ^^


2. E 타입과 U 타입이 identity conversion 또는 공변일 때, E 타입의 1차원 배열을 ReadOnlySpan<U>로 암시적 형변환

이와 연관해서는 C# 13을 기준으로 미리 이전 글에서 한번 설명했습니다.

C# - 배열 및 Span의 공변성
; https://www.sysnet.pe.kr/2/0/13973

C# 14부터 달라진 점은, 더 이상 Span<U> 타입으로의 변환을 지원하지 않고 오직 ReadOnlySpan<U>만 지원한다는 것인데요,

public class Person { /* ...[생략]... */ }

public class Employee : Person { /* ...[생략]... */ }

internal class Program
{
    static void Main(string[] args)
    {
        Employee[] employees = {
            new Employee("Alice", 30, "Developer"),
            new Employee("Bob", 40, "Manager"),
            new Employee("Charlie", 35, "Designer")
        };

        // C# 14부터 컴파일 오류
        // PrintPerson(employees);

        // C# 14부터 ReadOnlySpan<Person>로 암시적 형변환  
        Print(employees);
    }

    static void PrintPerson(Span<Person> span)
    {
        for (int i = 0; i < span.Length; i++)
        {
            Console.WriteLine(span[i]);
        }
    }

    static void Print(ReadOnlySpan<Person> span)
    {
        for (int i = 0; i < span.Length; i++)
        {
            Console.WriteLine(span[i]);
        }
    }
}

즉, 하위 호환성이 깨진 경우입니다.

Breaking changes in Roslyn after .NET 9.0.100 through .NET 10.0.100
 - Span<T> and ReadOnlySpan<T> overloads are applicable in more scenarios in C# 14 and newer
; https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/breaking-changes/compiler%20breaking%20changes%20-%20dotnet%2010#spant-and-readonlyspant-overloads-are-applicable-in-more-scenarios-in-c-14-and-newer


3. E 타입과 U 타입이 identity conversion 또는 공변일 때, E 타입의 Span<E> 타입을 ReadOnlySpan<U> 타입으로 암시적 형변환

이 규칙은 C# 14부터 새롭게 추가된 것으로, 다음의 예제와 같이 Span<Employee> 타입을 ReadOnlySpan<Person> 타입으로 암시적 형변환할 수 있습니다.

static void PrintEmployee(Span<Employee> span)
{
    // C# 14부터 ReadOnlySpan<Person>으로 암시적 형변환 가능
    Print(span);
}

static void Print(ReadOnlySpan<Person> span)
{
    for (int i = 0; i < span.Length; i++)
    {
        Console.WriteLine(span[i]);
    }
}

부가적으로, 위의 코드를 컴파일하려면 .NET 9+ 런타임이 필요하다는 점에 유의해야 합니다. 그렇지 않으면 "error CS0656: Missing compiler required member 'ReadOnlySpan<T>.CastUp'" 컴파일 오류가 발생하는데요, 다시 말해, .NET 9 BCL의 ReadOnlySpan<T> 타입에 CastUp 메서드가 추가돼 C# 14 컴파일러가 활용할 수 있게 된 것입니다.


4. E 타입이 U 타입에 대해 identity conversion 또는 공변일 때, ReadOnlySpan<E> 타입을 ReadOnlySpan<U> 타입으로 암시적 형변환

위의 3번 규칙에서 Span<E>에서 ReadOnlySpan<U>로 형변환이 가능했던 것처럼, C# 14부터 ReadOnlySpan<E> 타입을 ReadOnlySpan<U> 타입으로 암시적 형변환할 수 있습니다.

static void PrintEmployee(ReadOnlySpan<Employee> span)
{
    // C# 14부터 ReadOnlySpan<Person>으로 암시적 형변환 가능
    Print(span);
}

static void Print(ReadOnlySpan<Person> span)
{
    for (int i = 0; i < span.Length; i++)
    {
        Console.WriteLine(span[i]);
    }
}

또한 이것 역시 .NET 9+ 런타임이 필요합니다.


5. string 타입을 System.ReadOnlySpan<char> 타입으로 암시적 형변환

C# 13에서도 가능했었기 때문에 새로울 것은 없으니 아래의 예제로 대체하겠습니다.

PrintString("Hello, World!"); // 문자열 리터럴에서도, 
string text = "Hello, World!";
PrintString(text); // string 인스턴스도 ReadOnlySpan<char>로 암시적 형변환

static void PrintString(ReadOnlySpan<char> text)
{
    foreach (var ch in text)
    {
        Console.Write(ch);
    }

    Console.WriteLine();
}




자, 이렇게 해서 마이크로소프트는 (제목을 ^^ "First-Class Span Types #7905"라고 지었을 정도니까) C#에 Span 타입을 배열에 준하는 수준으로 언어에 자연스럽게 녹아냈다고 평가하는 것 같습니다.

제가 보기에도 이 정도면, (ref struct라는 특성상) 일반 class/struct의 멤버로 정의할 수 없다는 점을 제외하면 배열과 거의 차이가 없다고 봐도 무방할 정도입니다. (굳이 필드로 정의해야 한다면 Memory<T>라는 대안도 있긴 합니다.)

그나저나, 제가 C# 언어에 대한 책을 쓴 경험으로 느낀 건데요, 근래 들어 점점 더 C#의 신규 문법을 소개하기 위해 Spec 문서의 내용을 세세하게 알아야만 하는 경우가 생기는 것 같습니다. C# 13에서도 "Method group natural type improvements"을 설명하기 위해 아래의 내용을 써야만 했었고,

C# - Method Group, Natural Type, function_type
; https://www.sysnet.pe.kr/2/0/13680

이번에도 "Identity conversion"을 설명해야만 했으니... C# 언어 개발팀에서 한편으로는 열일하는 것도 같고... 다른 한편으로는 이제 넣을 수 있는 기능은 다 넣은 상태에서 버전 업은 해야겠다는 압박감에 쥐어짜는 것 같은 느낌도 드는군요. ^^;

물론, 이런 기능들이 편리하긴 하지만... 그에 따라 설명하는 것도 점점 더 어려워지는 것 같습니다.




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]






[최초 등록일: ]
[최종 수정일: 8/14/2025]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




... 61  62  63  64  65  66  67  68  69  70  71  72  73  [74]  75  ...
NoWriterDateCnt.TitleFile(s)
12175정성태3/8/202022952개발 환경 구성: 477. "Docker Desktop for Windows"의 "Linux Container" 모드를 위한 tcp 바인딩 추가
12174정성태3/7/202021145개발 환경 구성: 476. DockerDesktopVM의 파일 시스템 접근 [3]
12173정성태3/7/202023694개발 환경 구성: 475. docker - SQL Server 2019 컨테이너 실행 [1]
12172정성태3/7/202027873개발 환경 구성: 474. docker - container에서 root 권한 명령어 실행(sudo)
12171정성태3/6/202022339VS.NET IDE: 143. Visual Studio - ASP.NET Core Web Application의 "Enable Docker Support" 옵션으로 달라지는 점 [1]
12170정성태3/6/202019536오류 유형: 599. "Docker Desktop is switching..." 메시지와 DockerDesktopVM CPU 소비 현상
12169정성태3/5/202022446개발 환경 구성: 473. Windows nanoserver에 대한 docker pull의 태그 사용 [1]
12168정성태3/5/202024628개발 환경 구성: 472. 윈도우 환경에서의 dockerd.exe("Docker Engine" 서비스)가 Linux의 것과 다른 점
12167정성태3/5/202021598개발 환경 구성: 471. C# - 닷넷 응용 프로그램에서 DB2 Express-C 데이터베이스 사용 (3) - ibmcom/db2express-c 컨테이너 사용
12166정성태3/4/202024047개발 환경 구성: 470. Windows Server 컨테이너 - DockerMsftProvider 모듈을 이용한 docker 설치
12165정성태3/2/202021544.NET Framework: 900. 실행 시에 메서드 가로채기 - CLR Injection: Runtime Method Replacer 개선 - 네 번째 이야기(Monitor.Enter 후킹)파일 다운로드1
12164정성태2/29/202022536오류 유형: 598. Surface Pro 6 - Windows Hello Face Software Device가 인식이 안 되는 문제
12163정성태2/27/202021050.NET Framework: 899. 익명 함수를 가리키는 delegate 필드에 대한 직렬화 문제
12162정성태2/26/202027075디버깅 기술: 166. C#에서 만든 COM 객체를 C/C++로 P/Invoke Interop 시 메모리 누수(Memory Leak) 발생 [6]파일 다운로드2
12161정성태2/26/202022237오류 유형: 597. manifest - The value "x64" of attribute "processorArchitecture" in element "assemblyIdentity" is invalid.
12160정성태2/26/202021969개발 환경 구성: 469. Reg-free COM 개체 사용을 위한 manifest 파일 생성 도구 - COMRegFreeManifest
12159정성태2/26/202017429오류 유형: 596. Visual Studio - The project needs to include ATL support
12158정성태2/25/202021752디버깅 기술: 165. C# - Marshal.GetIUnknownForObject/GetIDispatchForObject 사용 시 메모리 누수(Memory Leak) 발생파일 다운로드1
12157정성태2/25/202020813디버깅 기술: 164. C# - Marshal.GetNativeVariantForObject 사용 시 메모리 누수(Memory Leak) 발생 및 해결 방법파일 다운로드1
12156정성태2/25/202019257오류 유형: 595. LINK : warning LNK4098: defaultlib 'nafxcw.lib' conflicts with use of other libs; use /NODEFAULTLIB:library
12155정성태2/25/202020036오류 유형: 594. Warning NU1701 - This package may not be fully compatible with your project
12154정성태2/25/202018686오류 유형: 593. warning LNK4070: /OUT:... directive in .EXP differs from output filename
12153정성태2/23/202024043.NET Framework: 898. Trampoline을 이용한 후킹의 한계파일 다운로드1
12152정성태2/23/202021033.NET Framework: 897. 실행 시에 메서드 가로채기 - CLR Injection: Runtime Method Replacer 개선 - 세 번째 이야기(Trampoline 후킹)파일 다운로드1
12151정성태2/22/202023548.NET Framework: 896. C# - Win32 API를 Trampoline 기법을 이용해 C# 메서드로 가로채는 방법 - 두 번째 이야기 (원본 함수 호출)파일 다운로드1
12150정성태2/21/202023801.NET Framework: 895. C# - Win32 API를 Trampoline 기법을 이용해 C# 메서드로 가로채는 방법 [1]파일 다운로드1
... 61  62  63  64  65  66  67  68  69  70  71  72  73  [74]  75  ...