Microsoft MVP성태의 닷넷 이야기
.NET Framework: 1116. C# 10 - (15) CallerArgumentExpression 특성 추가 [링크 복사], [링크+제목 복사],
조회: 20429
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
(연관된 글이 1개 있습니다.)
(시리즈 글이 15개 있습니다.)
.NET Framework: 1094. C# 10 - (1) 구조체를 생성하는 record struct
; https://www.sysnet.pe.kr/2/0/12790

.NET Framework: 1096. C# 10 - (2) 전역 네임스페이스 선언
; https://www.sysnet.pe.kr/2/0/12792

.NET Framework: 1097. C# 10 - (3) 개선된 변수 초기화 판정
; https://www.sysnet.pe.kr/2/0/12793

.NET Framework: 1099. C# 10 - (4) 상수 문자열에 포맷 식 사용 가능
; https://www.sysnet.pe.kr/2/0/12796

.NET Framework: 1100. C# 10 - (5) 속성 패턴의 개선
; https://www.sysnet.pe.kr/2/0/12799

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

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

.NET Framework: 1104. C# 10 - (8) 분해 구문에서 기존 변수의 재사용 가능
; https://www.sysnet.pe.kr/2/0/12805

.NET Framework: 1105. C# 10 - (9) 비동기 메서드가 사용할 AsyncMethodBuilder 선택 가능
; https://www.sysnet.pe.kr/2/0/12807

.NET Framework: 1108. C# 10 - (10) 개선된 #line 지시자
; https://www.sysnet.pe.kr/2/0/12812

.NET Framework: 1109. C# 10 - (11) Lambda 개선
; https://www.sysnet.pe.kr/2/0/12813

.NET Framework: 1113. C# 10 - (12) 문자열 보간 성능 개선
; https://www.sysnet.pe.kr/2/0/12826

.NET Framework: 1114. C# 10 - (13) 단일 파일 내에 적용되는 namespace 선언
; https://www.sysnet.pe.kr/2/0/12828

.NET Framework: 1115. C# 10 - (14) 구조체 타입에 기본 생성자 정의 가능
; https://www.sysnet.pe.kr/2/0/12829

.NET Framework: 1116. C# 10 - (15) CallerArgumentExpression 특성 추가
; https://www.sysnet.pe.kr/2/0/12835




C# 10 - (15) 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://learn.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) 문자열 보간 성능 개선 (공식 문서, Interpolated string improvements)
; https://www.sysnet.pe.kr/2/0/12826

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

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

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

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




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

[연관 글]






[최초 등록일: ]
[최종 수정일: 3/1/2023]

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

비밀번호

댓글 작성자
 



2022-07-04 03시47분
[semir4in] 함수를 통과하면 입력 변수의 이름 대신 매개 변수의 이름만 얻게 됐었는데, CallerArgumentExpression 으로 해결할 수 있게 됐네요. 테스트 케이스 작성할 때 큰 도움이 됐습니다. 고맙습니다!
[guest]
2022-07-25 09시33분
참고로 이 기능은 C/C++의 문자열화 연산화 "#"를 사용한 매크로와 유사합니다.

Stringizing operator (#)
; https://learn.microsoft.com/en-us/cpp/preprocessor/stringizing-operator-hash

3.4 Stringizing
; https://gcc.gnu.org/onlinedocs/cpp/Stringizing.html#Stringizing
정성태

... 61  62  63  64  65  66  67  68  69  70  71  72  73  74  [75]  ...
NoWriterDateCnt.TitleFile(s)
12153정성태2/23/202024384.NET Framework: 898. Trampoline을 이용한 후킹의 한계파일 다운로드1
12152정성태2/23/202021410.NET Framework: 897. 실행 시에 메서드 가로채기 - CLR Injection: Runtime Method Replacer 개선 - 세 번째 이야기(Trampoline 후킹)파일 다운로드1
12151정성태2/22/202024053.NET Framework: 896. C# - Win32 API를 Trampoline 기법을 이용해 C# 메서드로 가로채는 방법 - 두 번째 이야기 (원본 함수 호출)파일 다운로드1
12150정성태2/21/202024119.NET Framework: 895. C# - Win32 API를 Trampoline 기법을 이용해 C# 메서드로 가로채는 방법 [1]파일 다운로드1
12149정성태2/20/202021038.NET Framework: 894. eBEST C# XingAPI 래퍼 - 연속 조회 처리 방법 [1]
12148정성태2/19/202025719디버깅 기술: 163. x64 환경에서 구현하는 다양한 Trampoline 기법 [1]
12147정성태2/19/202021022디버깅 기술: 162. x86/x64의 기계어 코드 최대 길이
12146정성태2/18/202022218.NET Framework: 893. eBEST C# XingAPI 래퍼 - 로그인 처리파일 다운로드1
12145정성태2/18/202023836.NET Framework: 892. eBEST C# XingAPI 래퍼 - Sqlite 지원 추가파일 다운로드1
12144정성태2/13/202024012.NET Framework: 891. 실행 시에 메서드 가로채기 - CLR Injection: Runtime Method Replacer 개선 - 두 번째 이야기파일 다운로드1
12143정성태2/13/202018425.NET Framework: 890. 상황별 GetFunctionPointer 반환값 정리 - x64파일 다운로드1
12142정성태2/12/202022341.NET Framework: 889. C# 코드로 접근하는 MethodDesc, MethodTable파일 다운로드1
12141정성태2/10/202021340.NET Framework: 888. C# - ASP.NET Core 웹 응용 프로그램의 출력 가로채기 [2]파일 다운로드1
12140정성태2/10/202022701.NET Framework: 887. C# - ASP.NET 웹 응용 프로그램의 출력 가로채기파일 다운로드1
12139정성태2/9/202022385.NET Framework: 886. C# - Console 응용 프로그램에서 UI 스레드 구현 방법
12138정성태2/9/202028600.NET Framework: 885. C# - 닷넷 응용 프로그램에서 SQLite 사용 [6]파일 다운로드1
12137정성태2/9/202020243오류 유형: 592. [AhnLab] 경고 - 디버거 실행을 탐지했습니다.
12136정성태2/6/202021892Windows: 168. Windows + S(또는 Q)로 뜨는 작업 표시줄의 검색 바가 동작하지 않는 경우
12135정성태2/6/202027688개발 환경 구성: 468. Nuget 패키지의 로컬 보관 폴더를 옮기는 방법 [2]
12134정성태2/5/202024964.NET Framework: 884. eBEST XingAPI의 C# 래퍼 버전 - XingAPINet Nuget 패키지 [5]파일 다운로드1
12133정성태2/5/202022707디버깅 기술: 161. Windbg 환경에서 확인해 본 .NET 메서드 JIT 컴파일 전과 후 - 두 번째 이야기
12132정성태1/28/202025728.NET Framework: 883. C#으로 구현하는 Win32 API 후킹(예: Sleep 호출 가로채기) [1]파일 다운로드1
12131정성태1/27/202024462개발 환경 구성: 467. LocaleEmulator를 이용해 유니코드를 지원하지 않는(한글이 깨지는) 프로그램을 실행하는 방법 [1]
12130정성태1/26/202022031VS.NET IDE: 142. Visual Studio에서 windbg의 "Open Executable..."처럼 EXE를 직접 열어 디버깅을 시작하는 방법
12129정성태1/26/202029037.NET Framework: 882. C# - 키움 Open API+ 사용 시 Registry 등록 없이 KHOpenAPI.ocx 사용하는 방법 [3]
12128정성태1/26/202023168오류 유형: 591. The code execution cannot proceed because mfc100.dll was not found. Reinstalling the program may fix this problem.
... 61  62  63  64  65  66  67  68  69  70  71  72  73  74  [75]  ...