성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] VT sequences to "CONOUT$" vs. STD_O...
[정성태] NetCoreDbg is a managed code debugg...
[정성태] Evaluating tail call elimination in...
[정성태] What’s new in System.Text.Json in ....
[정성태] What's new in .NET 9: Cryptography ...
[정성태] 아... 제시해 주신 "https://akrzemi1.wordp...
[정성태] 다시 질문을 정리할 필요가 있을 것 같습니다. 제가 본문에...
[이승준] 완전히 잘못 짚었습니다. 댓글 지우고 싶네요. 검색을 해보...
[정성태] 우선 답글 감사합니다. ^^ 그런데, 사실 저 예제는 (g...
[이승준] 수정이 안되어서... byteArray는 BYTE* 타입입니다...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>C# 11 - 목록 패턴(List patterns)</h1> <p> 아래의 글에 보면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C# 11 Preview: List patterns ; <a target='tab' href='https://devblogs.microsoft.com/dotnet/early-peek-at-csharp-11-features/#c-11-preview-list-patterns'>https://devblogs.microsoft.com/dotnet/early-peek-at-csharp-11-features/#c-11-preview-list-patterns</a> </pre> <br /> C# 11에 새롭게 추가한 목록 패턴 매칭을 소개합니다. 정말이지, 마이크로소프트가 C#의 패턴 매칭에 진심이군요. ^^ 처음 도입된 C# 7 이후로 꾸준히 패턴 매칭 문법을 보완하더니,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C# 7 - <a target='tab' href='https://learn.microsoft.com/ko-kr/dotnet/csharp/language-reference/operators/patterns'>기본 패턴 매칭 기능</a> 추가 C# 8 - <a target='tab' href='https://learn.microsoft.com/ko-kr/dotnet/csharp/whats-new/csharp-8#switch-expressions'>switch 식, 속성 패턴, 튜플 패턴, 위치 패턴</a> 추가 C# 9 - <a target='tab' href='https://www.sysnet.pe.kr/2/0/12383'>"Type Patterns", "Relational Patterns", "Pattern Combinators", "Parenthesized Patterns"</a> 추가 C# 10 - <a target='tab' href='https://www.sysnet.pe.kr/2/0/12799'>속성 패턴 개선</a> </pre> <br /> C# 11에는 또다시 목록 패턴까지 추가했습니다. 간단하게 코드 먼저 볼까요? ^^<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > int[] arr1 = { 1, 2, 10 }; int[] arr2 = { 1, 2, 5, 10 }; int[] arr3 = { 1, 2, 5, 6, 7, 8, 9, 10 }; int[] arr4 = { 1, 3 }; int[] arr5 = { 1, 3, 6 }; int[] arr6 = { 2, 3 }; Console.WriteLine(CheckSwitch(arr1)); // 1 Console.WriteLine(CheckSwitch(arr2)); // 1 Console.WriteLine(CheckSwitch(arr3)); // 1 Console.WriteLine(CheckSwitch(arr4)); // 2 if (arr5 is <span style='color: blue; font-weight: bold'>[1, ..]</span>) { Console.WriteLine(3); // 3 } Console.WriteLine(CheckSwitch(arr6)); // 50 static int CheckSwitch(int[] values) => values switch { <span style='color: blue; font-weight: bold'>[1, 2, .., 10] => 1, [1, _] => 2, [1, ..] => 3, [..] => 50</span> }; </pre> <br /> 보시면, 목록의 패턴 매칭을 돕기 위해 그 자체에 슬라이스 패턴(..)과 무시 패턴(_)을 함께 제공하고 있습니다. 단지, switch 식의 경우엔 is와는 달리 그 특성상 "default" 경우를 위해 단독 슬라이스 패턴인 "[..]"을 마지막에 하나 제공해야 한다는 정도의 (없으면 경고를 주는) 추가 규칙이 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > List<int> list1 = new List<int>(new[] { 1, 3 }); Console.WriteLine(CheckSwitch(list1)); // 3 static int CheckSwitch(int[] values) => values switch { [1, 2, .., 10] => 1, [1, _] => 2, [1, ..] => 3, <span style='color: blue; font-weight: bold'>[..] => 50</span> // 없으면 warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). }; static int CheckSwitch(List<int> values) => values switch { [1, 2] => 1, [1, _] => 2, <span style='color: blue; font-weight: bold'>[..] => 3,</span> // 없으면 warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). }; </pre> <br /> 또한, 조건이 겹치는 패턴을 사용해도 오류가 발생합니다. 일례로 아래는 조건식 자체는 다르지만 결국 같은 조건에 해당하므로 컴파일 오류가 발생합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > static int CheckSwitch(IList<int> values) { switch (values) { // error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match. <span style='color: blue; font-weight: bold'>case [_, .., 1]: return 1; case [.., _, 1]: return 2;</span> } return 0; } </pre> <br /> 반면, 아래는 2개의 조건이 확실하게 다르므로 잘 동작합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > IList<int> list1 = new List<int>(new[] { 1, 1, 2, 3 }); Console.WriteLine(CheckSwitch(list1)); // 1 IList<int> list2 = new List<int>(new[] { 5, 6, 1, 9 }); Console.WriteLine(CheckSwitch(list2)); // 2 static int CheckSwitch(IList<int> values) { const int condition = 1; switch (values) { case <span style='color: blue; font-weight: bold'>[_, 1, ..]</span>: return 1; case <span style='color: blue; font-weight: bold'>[.., condition, _]</span>: return 2; } return 0; } </pre> <br /> 나아가 기존의 패턴 문법과 병용한다면 좀 더 풍부한 조건을 만들 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > ArrayList arr1 = new ArrayList(new[] { 1, 3, 5 }); Console.WriteLine(CheckSwitch(arr1)); // 1 ArrayList arr2 = new ArrayList(new[] { 1, 10, 5 }); Console.WriteLine(CheckSwitch(arr2)); // 1 static int CheckSwitch(ArrayList values) => values switch { [_, <span style='color: blue; font-weight: bold'>>= 3</span>, ..] <span style='color: blue; font-weight: bold'>or</span> [_, <= 10, ..] <span style='color: blue; font-weight: bold'>=> 1</span>, [..] => -1, }; List<int[]> list = new List<int[]>(new[] { new[] { 1, 10, 5 } }); Console.WriteLine(CheckSwitch(list)); // 1 static int CheckSwitch(List<int[]> values) => values switch { [ <span style='color: blue; font-weight: bold'>[1, .., 5]</span> ] => 1, [..] => -1, }; </pre> <br /> 목록 패턴을 위한 대상은 다음의 요건만 갖추면 어떤 객체든 올 수 있습니다.<br /> <br /> <ol> <li>Count 또는 Length 속성 제공</li> <li>indexer 속성 제공</li> </ol> <br /> 대개의 경우, 위와 같은 조건은 <a target='tab' href='https://learn.microsoft.com/en-us/dotnet/api/system.collections.ilist'>IList 인터페이스</a>를 구현하면 만족하는데요, 어쨌든 최대한 간단하게 위의 목록을 만족하는 클래스는 이런 식으로 정의할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <span style='color: blue; font-weight: bold'>NaturalNumber list = new NaturalNumber();</span> if (list is <span style='color: blue; font-weight: bold'>[1, .., Int32.MaxValue]</span>) { Console.WriteLine(true); // True } public class NaturalNumber { int _length = Int32.MaxValue; public <span style='color: blue; font-weight: bold'>int this[int index]</span> { get { return index + 1; } } public <span style='color: blue; font-weight: bold'>int Length</span> => _length; // 또는, // public int Count => _length; } </pre> <br /> 마지막으로, 패턴 내의 슬라이스 기호(..)로 대표되는 결과를 변수로 받아오는 것도 가능합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // 예제 코드: <a target='tab' href='https://devblogs.microsoft.com/dotnet/early-peek-at-csharp-11-features/'>https://devblogs.microsoft.com/dotnet/early-peek-at-csharp-11-features/</a> public static string CaptureSlice(int[] values) => values switch { [1, <span style='color: blue; font-weight: bold'>.. var middle</span>, _] => $"Middle {String.Join(", ", <span style='color: blue; font-weight: bold'>middle</span>)}", [<span style='color: blue; font-weight: bold'>.. var all</span>] => $"All {String.Join(", ", <span style='color: blue; font-weight: bold'>all</span>)}" }; </pre> <br /> 사용자 타입에서 저렇게 슬라이스 기호를 이용한 변수를 사용하려면 그에 따라 <a target='tab' href='https://www.sysnet.pe.kr/2/0/11835'>System.Range</a>를 받아들이는 indexer를 함께 구현해야 합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > NaturalNumber list = new NaturalNumber(); if (list is [1, <span style='color: blue; font-weight: bold'>.. var middle</span>, Int32.MaxValue]) { foreach (var elem in <span style='color: blue; font-weight: bold'>middle.Take(10)</span>) { Console.Write($"{elem},"); // 출력 결과: 2,3,4,5,6,7,8,9,10,11, } } public class NaturalNumber { int _length = Int32.MaxValue; public int this[int index] { get { return index + 1; } set { } } <span style='color: blue; font-weight: bold'>public IEnumerable<int> this[System.Range range] { get { int startPos = range.Start.Value + 1; int endPos = _length - range.End.Value - startPos + 1; if (range.End.IsFromEnd == false) { endPos = range.End.Value - startPos + 1; } return Enumerable.Range(startPos, endPos); } }</span> public int Length => _length; // 또는, // public int Count => Int32.MaxValue; } </pre> <br /> 한 가지 제약이라면, 슬라이스로 지정한 영역을 변수로 받아오는 것은 (and는 가능하지만) not, or 패턴이 함께 지정된 목록 패턴에서는 사용할 수 없습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // A variable may not be declared within a 'not' or 'or' pattern. [_, >= 3, ..] or [_, <= 10, <span style='color: blue; font-weight: bold'>.. var rest</span>] => 1, </pre> <br /> 따지고 보면 당연한 결과입니다. or 패턴의 경우 "Short-circuit Evaluation"이 발생하는 데다 변수로 받게 되는 결과가 해당 조건이 참이어서 받는 경우라면 상관없겠지만 다른 or 조건이 참이어서 받는 경우라면 가능하지 않는 상황일 수 있기 때문입니다. not 패턴 역시 그 조건이 아닌 목록에 대해 슬라이스 영역을 받게 되는 것이므로 undefined와 같은 상태가 될 수 있습니다.<br /> <br /> (<a target='tab' href='https://www.sysnet.pe.kr/bbs/DownloadAttachment.aspx?fid=1957&boardid=331301885'>첨부 파일은 이 글의 예제 코드를 포함</a>합니다.)<br /> <br /> <hr style='width: 50%' /><br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C# 11 - 인터페이스 내에 정적 추상 메서드 정의 가능 (공식 문서, <a target='tab' href='https://github.com/dotnet/csharplang/issues/4436'>Static Abstract Members In Interfaces C# 10 Preview</a>) ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/12814'>https://www.sysnet.pe.kr/2/0/12814</a> C# 11 - 제네릭 타입의 특성 적용 (<a target='tab' href='https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-11#generic-attributes'>공식 문서</a>, <a target='tab' href='https://github.com/dotnet/csharplang/issues/124'>Generic attributes</a>) ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/12839'>https://www.sysnet.pe.kr/2/0/12839</a> C# 11 - 사용자 정의 checked 연산자 (공식 문서, <a target='tab' href='https://github.com/dotnet/csharplang/blob/main/proposals/checked-user-defined-operators.md'>Checked user-defined operators</a>) ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/13099'>https://www.sysnet.pe.kr/2/0/13099</a> C# 11 - shift 연산자 재정의에 대한 제약 완화 (공식 문서, <a target='tab' href='https://github.com/dotnet/csharplang/issues/4666'>Relaxing Shift Operator</a>) ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/13100'>https://www.sysnet.pe.kr/2/0/13100</a> C# 11 - IntPtr/UIntPtr과 nint/unint의 통합 (<a target='tab' href='https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-11#numeric-intptr-and-uintptr'>공식 문서</a>, <a target='tab' href='https://github.com/dotnet/csharplang/blob/main/proposals/numeric-intptr.md'>Numeric IntPtr</a>) ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/13111'>https://www.sysnet.pe.kr/2/0/13111</a> C# 11 - 새로운 연산자 ">>>" (Unsigned Right Shift) (공식 문서, <a target='tab' href='https://github.com/dotnet/csharplang/issues/4682'>Unsigned right shift operator</a>) ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/13110'>https://www.sysnet.pe.kr/2/0/13110</a> C# 11 - 원시 문자열 리터럴 (<a target='tab' href='https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-11#raw-string-literals'>공식 문서</a>, <a target='tab' href='https://github.com/dotnet/csharplang/blob/main/proposals/raw-string-literal.md'>raw string literals</a>) ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/13085'>https://www.sysnet.pe.kr/2/0/13085</a> C# 11 - 문자열 보간 개선 2가지 (<a target='tab' href='https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-11#newlines-in-string-interpolations'>공식 문서</a>, <a target='tab' href='https://github.com/dotnet/csharplang/issues/4935'>Allow new-lines in all interpolations</a>) ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/13086'>https://www.sysnet.pe.kr/2/0/13086</a> C# 11 - 목록 패턴 (공식 문서, <a target='tab' href='https://github.com/dotnet/csharplang/blob/main/proposals/list-patterns.md'>List patterns</a>) ; https://www.sysnet.pe.kr/2/0/13112 C# 11 - Span 타입에 대한 패턴 매칭 (<a target='tab' href='https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-11#pattern-match-spanchar-or-readonlyspanchar-on-a-constant-string'>공식 문서</a>, <a target='tab' href='https://github.com/dotnet/csharplang/issues/1881'>Pattern matching on ReadOnlySpan<char></a>) ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/13113'>https://www.sysnet.pe.kr/2/0/13113</a> C# 11 - Utf8 문자열 리터럴 지원 (공식 문서, <a target='tab' href='https://github.com/dotnet/csharplang/blob/main/proposals/utf8-string-literals.md'>Utf8 Strings Literals</a>) ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/13096'>https://www.sysnet.pe.kr/2/0/13096</a> C# 11 - ref struct에 ref 필드를 허용 (공식 문서, <a target='tab' href='https://github.com/dotnet/csharplang/blob/main/proposals/low-level-struct-improvements.md'>ref fields</a>) ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/13015'>https://www.sysnet.pe.kr/2/0/13015</a> C# 11 - 파일 범위 내에서 유효한 타입 정의 (공식 문서, <a target='tab' href='https://github.com/dotnet/csharplang/issues/6011'>File-local types</a>) ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/13117'>https://www.sysnet.pe.kr/2/0/13117</a> C# 11 - 메서드 매개 변수에 대한 nameof 지원 (<a target='tab' href='https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-11#extended-nameof-scope'>공식 문서</a>, <a target='tab' href='https://github.com/dotnet/csharplang/issues/373'>nameof(parameter)</a>) ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/13122'>https://www.sysnet.pe.kr/2/0/13122</a> C# 11 - 멤버(속성/필드)에 지정할 수 있는 required 예약어 추가 (공식 문서, <a target='tab' href='https://github.com/dotnet/csharplang/blob/main/proposals/required-members.md'>Required members</a>) ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/13123'>https://www.sysnet.pe.kr/2/0/13123</a> C# 11 - 구조체 필드의 자동 초기화 (공식 문서, <a target='tab' href='https://github.com/dotnet/csharplang/blob/main/proposals/auto-default-structs.md'>auto-default structs</a>) ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/13125'>https://www.sysnet.pe.kr/2/0/13125</a> C# 11 - 정적 메서드에 대한 delegate 처리 시 cache 적용 (공식 문서, <a target='tab' href='https://github.com/dotnet/roslyn/issues/5835'>Cache delegates for static method group</a>) ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/13126'>https://www.sysnet.pe.kr/2/0/13126</a> Language Feature Status ; <a target='tab' href='https://github.com/dotnet/roslyn/blob/main/docs/Language%20Feature%20Status.md'>https://github.com/dotnet/roslyn/blob/main/docs/Language%20Feature%20Status.md</a> </pre> </p><br /> <br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1229
(왼쪽의 숫자를 입력해야 합니다.)