Microsoft MVP성태의 닷넷 이야기
.NET Framework: 1116. C# 10 - (16) CallerArgumentExpression 특성 추가 [링크 복사], [링크+제목 복사]
조회: 1546
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일

C# 10 - (16) CallerArgumentExpression 특성 추가

지난 C# 5.0에 호출자 정보로 다음의 3가지 특성이 제공되었습니다.

C# 5.0에 새로 추가된 Caller Info 특성
; https://www.sysnet.pe.kr/2/0/1134

  • CallerMemberName
  • CallerFilePath
  • CallerLineNumber

그동안 이와 관련한 기능 추가가 없다가, C# 10에 들어서야 CallerArgumentExpression 특성 1개가 또 추가되는군요. ^^ 간단한 사용법을 보면 금방 어떤 것인지 이해가 되실 것입니다. ^^

using System.Runtime.CompilerServices;

public static class Program
{
    public static void Main(string [] args)
    {
        MyDebug.Assert(args.Length == 1);
        MyDebug.Assert(Environment.CurrentDirectory == "c:/temp");
    }
}

public static class MyDebug
{
    public static void Assert(bool condition, [CallerArgumentExpression("condition")] string message = null)
    {
        if (condition == false)
        {
            Console.WriteLine("Assert failed: " + message);
        }
    }
}

/* 출력 결과
Assert failed: args.Length == 1
Assert failed: Environment.CurrentDirectory == "c:/temp"
*/

보는 바와 같이 이전의 호출자 정보처럼 CallerArgumentExpression 특성이 붙은 인자는 기본값이 있어야 하고 그 특성에 전달된 "condition"은 해당 메서드에 전달된 또 다른 매개 변수의 이름이어야 합니다.

C# 10 컴파일러는, 저렇게 CallerArgumentExpression이 지정된 메서드가 호출되면, 지정된 이름의 매개 변수로 전달된 표현식을 문자열 그대로 특성이 지정된 변수에 전달합니다. 즉, 위의 소스 코드를 C# 10 컴파일러는 다음과 같이 변환해 빌드하는 것입니다.

public static class Program
{
    public static void Main(string [] args)
    {
        MyDebug.Assert(args.Length == 1, "args.Length == 1");
        MyDebug.Assert(Environment.CurrentDirectory == "c:/temp", "Environment.CurrentDirectory == \"c:/temp\"");
    }
}

실제로 이 기능의 공식 문서에는 진단/테스트 API들에서의 오류 메시지 보완을 위한 것이라고 나옵니다.

CallerArgumentExpression
; https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-10.0/caller-argument-expression

Allow developers to capture the expressions passed to a method, to enable better error messages in diagnostic/testing APIs and reduce keystrokes.

따라서 단위 테스트나 로깅 프로젝트를 사용할 때 유용하게 사용할 수 있을 것입니다.

참고로 이 기능 역시 "C# 10 - (3) 개선된 변수 초기화 판정"과 마찬가지로 Visual Studio 2022 Preview 3.1에서 빌드하면 .NET 5 + C# 9, .NET Framework + C# 10 프로젝트에서도 잘 동작합니다. 반면, Visual Studio 2019(16.11.1)에서 빌드하면 동작하지 않습니다.

(첨부 파일은 이 글의 예제 코드를 포함합니다.)




그나저나, 위와 같은 경우에 아쉽게도 CallerArgumentExpression에 인자의 이름을 문자열로 하드 코딩해 전달해야 하는 것을 nameof로 바꾸면 좋지 않을까요?

public static void Assert(bool condition, [CallerArgumentExpression("condition")] string message = null)

public static void Assert(bool condition, [CallerArgumentExpression(nameof(condition))] string message = null)

저런 경우는 "C# 10 - (13) 문자열 보간 성능 개선"에서도 InterpolatedStringHandlerArgument를 지정할 때도 나옵니다.

public static string Create(IFormatProvider provider, 
    [InterpolatedStringHandlerArgument("provider")] ref DefaultInterpolatedStringHandler handler) =>
        handler.ToStringAndClear();

public static string Create(IFormatProvider provider, 
    [InterpolatedStringHandlerArgument(nameof(provider))] ref DefaultInterpolatedStringHandler handler) =>
        handler.ToStringAndClear();

아쉽게도 C# 10에서는 오류가 발생하지만, 현재 "C# Next"로 "nameof(parameter)"가 예정돼 있으니 조금만 기다리시면 되겠습니다. ^^




C# 10 - (1) 구조체를 생성하는 record struct (공식 문서, Static Abstract Members In Interfaces C# 10 Preview)
; https://www.sysnet.pe.kr/2/0/12790

C# 10 - (2) 전역 네임스페이스 선언 (공식 문서, Global Using Directive)
; https://www.sysnet.pe.kr/2/0/12792

C# 10 - (3) 개선된 변수 초기화 판정 (공식 문서, Improved Definite Assignment)
; https://www.sysnet.pe.kr/2/0/12793

C# 10 - (4) 상수 문자열에 포맷 식 사용 가능 (공식 문서, Constant Interpolated Strings)
; https://www.sysnet.pe.kr/2/0/12796

C# 10 - (5) 속성 패턴의 개선 (공식 문서, Extended property patterns)
; https://www.sysnet.pe.kr/2/0/12799

C# 10 - (6) record class 타입의 ToString 메서드를 sealed 처리 허용 (공식 문서, Sealed record ToString)
; https://www.sysnet.pe.kr/2/0/12801

C# 10 - (7) Source Generator V2 APIs (Source Generator V2 APIs)
; https://www.sysnet.pe.kr/2/0/12804

C# 10 - (8) 분해 구문에서 기존 변수의 재사용 가능 (공식 문서, Mix declarations and variables in deconstruction)
; https://www.sysnet.pe.kr/2/0/12805

C# 10 - (9) 비동기 메서드가 사용할 AsyncMethodBuilder 선택 가능 (공식 문서, Async method builder override); 
; https://www.sysnet.pe.kr/2/0/12807

C# 10 - (10) 개선된 #line 지시자 (공식 문서, Enhanced #line directive)
; https://www.sysnet.pe.kr/2/0/12812

C# 10 - (11) Lambda 개선 (공식 문서 1, 공식 문서 2, Lambda improvements) 
; https://www.sysnet.pe.kr/2/0/12813

C# 10 - (12) 인터페이스 내에 정적 추상 메서드 정의 가능(공식 문서, Static Abstract Members In Interfaces C# 10 Preview)
; https://www.sysnet.pe.kr/2/0/12814

C# 10 - (13) 문자열 보간 성능 개선 (공식 문서, Interpolated string improvements)
; https://www.sysnet.pe.kr/2/0/12826

C# 10 - (14) 단일 파일 내에 적용되는 namespace 선언 (공식 문서, File-scoped namespace)
; https://www.sysnet.pe.kr/2/0/12828

C# 10 - (15) 구조체 타입에 기본 생성자 정의 가능 (공식 문서, Parameterless struct constructors)
; https://www.sysnet.pe.kr/2/0/12829

C# 10 - (16) CallerArgumentExpression 특성 추가 (공식 문서, Caller expression attribute)
; https://www.sysnet.pe.kr/2/0/12835

C# 10 - (17) 제네릭 유형의 특성 허용 (공식 문서, Generic attributes)
; https://www.sysnet.pe.kr/2/0/12839

Language Feature Status
; https://github.com/dotnet/roslyn/blob/main/docs/Language%20Feature%20Status.md




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

[연관 글]






[최초 등록일: ]
[최종 수정일: 2/28/2022]

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

비밀번호

댓글 작성자
 




[1]  2  3  4  5  6  7  8  9  10  11  12  13  14  15  ...
NoWriterDateCnt.TitleFile(s)
13091정성태7/3/202231.NET Framework: 2027. C# - IPv4, IPv6를 모두 지원하는 서버 소켓 생성 방법
13090정성태6/29/202247오류 유형: 815. PyPI에 업로드한 패키지가 반영이 안 되는 경우
13089정성태6/28/202260개발 환경 구성: 646. HOSTS 파일 변경 시 Edge 브라우저에 반영하는 방법
13088정성태6/27/202253개발 환경 구성: 645. "Developer Command Prompt for VS 2022" 명령행 환경의 폰트를 바꾸는 방법
13087정성태6/23/2022125스크립트: 41. 파이썬 - FastAPI / uvicorn 호스팅 환경에서 asyncio 사용하는 방법
13086정성태6/22/2022215.NET Framework: 2026. C# 11 - 문자열 보간 개선 2가지파일 다운로드1
13085정성태6/22/2022177.NET Framework: 2025. C# 11 - 원시 문자열 리터럴(raw string literals)파일 다운로드1
13084정성태6/21/202266개발 환경 구성: 644. Windows - 파이썬 2.7을 msi 설치 없이 구성하는 방법
13083정성태6/20/2022183.NET Framework: 2024. .NET 7에 도입된 GC의 메모리 해제에 대한 segment와 region의 차이점
13082정성태6/19/2022114.NET Framework: 2023. C# - Process의 I/O 사용량을 보여주는 GetProcessIoCounters Win32 API파일 다운로드1
13081정성태6/17/2022180.NET Framework: 2022. C# - .NET 7 Preview 5 신규 기능 - System.IO.Stream ReadExactly / ReadAtLeast파일 다운로드1
13080정성태6/17/2022102개발 환경 구성: 643. Visual Studio 2022 17.2 버전에서 C# 11 또는 .NET 7.0 preview 적용
13079정성태6/17/202283오류 유형: 814. 파이썬 - Error: The file/path provided (...) does not appear to exist
13078정성태6/16/2022175.NET Framework: 2021. WPF - UI Thread와 Render Thread파일 다운로드1
13077정성태6/15/2022112스크립트: 40. 파이썬 - postgresql 환경 구성
13075정성태6/15/2022184Linux: 50. Linux - apt와 apt-get의 차이 [2]
13074정성태6/13/2022187.NET Framework: 2020. C# - NTFS 파일에 사용자 정의 속성값 추가하는 방법파일 다운로드1
13073정성태6/12/2022225Windows: 207. Windows Server 2022에 도입된 WSL 2
13072정성태6/10/2022146Linux: 49. Linux - ls 명령어로 출력되는 디렉터리 색상 변경 방법
13071정성태6/9/2022183스크립트: 39. Python에서 cx_Oracle 환경 구성
13070정성태6/8/2022235오류 유형: 813. Windows 11에서 입력 포커스가 바뀌는 문제 [1]
13069정성태5/26/2022474.NET Framework: 2019. C# - .NET에서 제공하는 3가지 Timer 비교
13068정성태5/24/2022392.NET Framework: 2018. C# - 일정 크기를 할당하는 동안 GC를 (가능한) 멈추는 방법파일 다운로드1
13067정성태5/23/2022209Windows: 206. Outlook - 1년 이상 지난 메일이 기본적으로 안 보이는 문제
13066정성태5/23/2022223Windows: 205. Windows 11 - Windows + S(또는 Q)로 뜨는 작업 표시줄의 검색 바가 동작하지 않는 경우
[1]  2  3  4  5  6  7  8  9  10  11  12  13  14  15  ...