성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] 그냥 RSS Reader 기능과 약간의 UI 편의성 때문에 사용...
[이종효] 오래된 소프트웨어는 보안 위협이 되기도 합니다. 혹시 어떤 기능...
[정성태] @Keystroke IEEE의 문서를 소개해 주시다니... +_...
[손민수 (Keystroke)] 괜히 듀얼채널 구성할 때 한번에 같은 제품 사라고 하는 것이 아...
[정성태] 전각(Full-width)/반각(Half-width) 기능을 토...
[정성태] Vector에 대한 내용은 없습니다. Vector가 닷넷 BCL...
[orion] 글 읽고 찾아보니 디자인 타임에는 InitializeCompon...
[orion] 연휴 전에 재현 프로젝트 올리자 생각해 놓고 여의치 않아서 못 ...
[정성태] 아래의 글에 정리했으니 참고하세요. C# - Typed D...
[정성태] 간단한 재현 프로젝트라도 있을까요? 저런 식으로 설명만 해...
글쓰기
제목
이름
암호
전자우편
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# 12 - 모든 형식의 별칭(Using aliases for any type)</h1> <p> <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://github.com/dotnet/csharplang/issues/4284'>Using aliases for any type</a>) ; <a target='tab' href='https://learn.microsoft.com/ko-kr/dotnet/csharp/whats-new/csharp-12#alias-any-type'>https://learn.microsoft.com/ko-kr/dotnet/csharp/whats-new/csharp-12#alias-any-type</a> </pre> <br /> <hr style='width: 50%' /><br /> <br /> 기존에도 using을 이용하면 네임스페이스 및 타입에 대해 별칭을 지정할 수 있었습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > using My = Universe; // 네임스페이스의 별칭 using Cio = System.Console; // 타입의 별칭 using static System.Diagnostics.Trace; // 편의상 정적 타입명 생략도 지원 internal class Program { private static void Main(string[] args) { My.Galaxy instance = new My.Galaxy { Name = "Milky way galaxy" }; Cio.WriteLine(instance.Name); WriteLine("TEST"); // System.Diagnostics.Trace } } namespace Universe { public class Galaxy { public string? Name { get; set; } } } </pre> <br /> 이름 충돌을 방지하기 위해 제공하던 별칭을 이제 C# 12부터는, 이름이 없는 타입(unnamed type), 포인터 타입, 널 가능한 타입에 대해서도 별칭을 지정하는 것이 가능해졌습니다. 즉, 어떤 타입이든 별칭을 만들 수 있게 된 것입니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 우선 이름이 없는 타입에 대한 별칭을 볼까요? ^^<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'>using Person = (int Age, string Name);</span> internal class Program { private static void Main(string[] args) { <span style='color: blue; font-weight: bold'>Person person = new Person { Age = 1, Name = "Anders" };</span> Console.WriteLine(person.Age); } } </pre> <br /> 어찌 보면, 이름이 없는 타입에 별칭을 부여함으로써 이름을 가진 타입이 된 것입니다. 여기서 재미있는 것은, 별칭으로 지정한 타입은 다음과 같이 "new" 없이 초기화하는 것도 가능하다는 점입니다.<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'>Person person = (1, "Anders");</span> Console.WriteLine(person.Age); } </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;' > using System; using System.Runtime.CompilerServices; internal class Program { [NullableContext(1)] private static void Main(string[] args) { // Person person = (1, "Anders"); 코드가 아래와 같이 변환됨 <span style='color: blue; font-weight: bold'>ValueTuple<int, string> valueTuple = new ValueTuple<int, string>(1, "Anders");</span> // Person person = new Person { Age = 1, Name = "Anders" }; 코드가 아래와 같이 변환됨 <span style='color: blue; font-weight: bold'>ValueTuple<int, string> valueTuple2 = new ValueTuple<int, string></span> { Item1 = 1, Item2 = "Anders" }; } } </pre> <br /> 튜플에 대한 C#의 단축 표현을 고려해 보면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > ValueTuple<int, string> t = (42, "Anders"); </pre> <br /> unnamed 타입에 대한 new 없는 형식이 이해가 됩니다. 따라서 만약 unnamed 타입을 별칭으로 받을 때 매개변수 이름을 지정하지 않는다면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > using Person = (int, string); </pre> <br /> 개별 요소에 대한 접근도 (튜플이므로) Item1, Item2, ... 식으로 접근하게 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > { Person person = (1, "Anders"); Console.WriteLine(person.Item1); // Item1 == 첫 번째 int 요소 접근 } </pre> <br /> <hr style='width: 50%' /><br /> <br /> 그다음 포인터 타입에 대해서도 별칭이 가능합니다. <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'>using unsafe BytePtr = byte*;</span> internal class Program { private unsafe static void Main(string[] args) { byte[] buffer = new byte[] { 1, 2, 3 }; <span style='color: blue; font-weight: bold'>fixed(BytePtr ptr = buffer)</span> { Console.WriteLine(*ptr); // 출력 결과: 1 } } } </pre> <br /> 포인터를 다루므로 자연스럽게 "unsafe"를 지정해야 하는 차이 정도만 있을 뿐 말 그대로 별칭으로 동작합니다.<br /> <br /> 널 가능한 타입(NRT: Nullable Reference Type)에 대해서도 마저 알아볼까요? ^^ 이에 대해서는 한 가지 제약을 두고 있는데요, 바로 "참조형"의 NRT에 대해서는 별칭을 둘 수 없다는 것입니다.<br /> <br /> 즉, 다음의 코드는,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > using Utf16String = System.String?; // 컴파일 에러: error CS9132: Using alias cannot be a nullable reference type. </pre> <br /> 허용하지 않으므로 System.String 그대로 별칭을 정의해야 합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > using Utf16String = string; // C# 12에서 가능 using Utf16String = System.String; // C# 11 이하에서도 가능 </pre> <br /> 얼핏 이런 제약이 이상해 보이지만, 이것이 기존의 NRT 표현을 동일한 정책으로 적용할 수 있기 때문에,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // <Nullable>enable</Nullable> 문맥에서, Utf16String t1 = ""; // 경고 없이 컴파일 Utf16String? t2 = null; // 경고 없이 컴파일 Utf16String t3 = null; // 경고: warning CS8600: Converting null literal or possible null value to non-nullable type. </pre> <br /> 위의 코드를 보면 일면 이해가 됩니다. 참조 형식의 NRT에 대해서만 제약이 있기 때문에 그 외의 별칭은 모두 유효합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // 결국 List<T>에 대한 별칭이고, NRT 타입이 아니므로 가능 using X1 = System.Collections.Generic.List<string?>; // 참조 타입의 NRT가 아니므로 가능 using X2 = int?; </pre> <br /> 한 가지 재미있는 것은, using 별칭에서는 네임스페이스 선언에 독립적인 듯해서 다음과 같이 정의하면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > using System.Collections.Generic; using X = List<string>; // error CS0246: The type or namespace name 'List<>' could not be found (are you missing a using directive or an assembly reference?) </pre> <br /> 타입을 찾을 수 없다는 컴파일 오류가 발생합니다. <strike>현재 Preview 버전 단계라서 그런 것인지 지켜봐야 할 것 같습니다. ^^</strike><br /> <br /> <hr style='width: 50%' /><br /> <br /> 참고로, C# 3.0부터 구현된 익명(anonymouse) 타입과 이름이 없는 타입(unnamed type)은 다릅니다. 가령 아래와 같이 익명 타입을 사용하면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > var p = new { Age = 16, Name = "Anders" }; // 익명 타입 Console.WriteLine(p.Name); // 출력 결과: "Anders" </pre> <br /> 내부적으로 C# 컴파일러가 "<>f__AnonymousType0`2"라는 식의 이름으로 된 클래스를 만들어 대응하게 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > public class <>f__AnonymousType0`2 { public <>f__AnonymousType0`2(int age, string name) { } // Age, Name 속성 // Equals, GetHashCode, ToString 재정의 } </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;' > using Student = { int, string }; // 컴파일 에러 </pre> <br /> 따라서 이름 없는 타입에 대한 별칭이라고는 하지만, 엄밀히 Tuple에 대한 별칭을 지원한다고 보면 되고 그런 의미에서 봤을 때 사실 기존 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;' > using Person = System.ValueTuple<int, string>; Person p1 = (42, "Anders"); Console.WriteLine(p1); // 출력 결과: (42, Anders) </pre> <br /> C# 12에서는 좀 더 간결한 지원을 추가했다고 봐도 아주 다른 이야기는 아닙니다. ^^<br /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1707
(왼쪽의 숫자를 입력해야 합니다.)