Microsoft MVP성태의 닷넷 이야기
.NET Framework: 1116. C# 10 - (15) CallerArgumentExpression 특성 추가 [링크 복사], [링크+제목 복사],
조회: 17482
글쓴 사람
정성태 (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
정성태

... 136  137  138  139  140  [141]  142  143  144  145  146  147  148  149  150  ...
NoWriterDateCnt.TitleFile(s)
1530정성태11/5/201327465기타: 38. 오픈소스로 풀린 하드 디스크 관리 도구 - WindowSMART
1529정성태11/5/201323350오류 유형: 192. SQL 서버 - The transaction log for database '...' is full due to 'LOG_BACKUP'.
1528정성태11/5/201328943디버깅 기술: 58. windbg 분석 사례 - WPF 응용 프로그램의 UI가 반응하지 않는 문제 [5]
1527정성태11/4/201326562VC++: 72. error MIDL2311 - mktyplib compatability mode 컴파일 오류
1526정성태11/3/201323264디버깅 기술: 57. C# - double 값에 대한 windbg 확인
1525정성태11/2/201329660.NET Framework: 391. C# - EXE/DLL로부터 추출한 이미지/아이콘의 배경색 투명 처리 [8]
1524정성태11/2/201330494기타: 37. 프로그램에 보여지는 리소스(예: 아이콘) 추출하는 방법 [1]
1523정성태11/2/201326864VS.NET IDE: 81. Visual Studio 확장 도구 AttachToW3WP - w3wp.exe에 대한 디버거 연결을 자동화하는 도구 [2]
1522정성태11/1/201323444VS.NET IDE: 80. IIS 8.0/8.5 - Global.asax.cs처럼 초기에 실행되는 코드에 Breakpoint를 잡는 방법
1521정성태11/1/201329304VS.NET IDE: 79. IIS 7.5 - Global.asax.cs처럼 초기에 실행되는 코드에 Breakpoint를 잡는 방법
1520정성태10/31/201323713오류 유형: 191. Visual Studio 2010 - 웹 애플리케이션 생성 시 "The project type is not supported by this installation." 오류 발생 해결
1519정성태10/31/201349238기타: 36. SYSTEM 또는 TrustedInstaller 소유로 되어 있는 폴더/파일을 삭제하는 방법 [5]
1518정성태10/30/201326894VS.NET IDE: 78. Visual Studio 확장으로 XmlCodeGenerator 제작하는 방법
1517정성태10/28/201326462디버깅 기술: 56. 덤프 파일에 핸들/스레드 정보를 포함하는 방법 [1]
1516정성태10/28/201331796.NET Framework: 390. FolderBrowserDialog보다 더 쓸만한 대화창이 필요하다면? [1]
1515정성태10/24/201334472VS.NET IDE: 77. Visual Studio 확장(VSIX) 만드는 방법 [5]
1514정성태10/24/201367804개발 환경 구성: 202. Internet Explorer 11을 7, 8, 9, 10 버전으로 인식시키는 방법 [9]파일 다운로드1
1513정성태10/23/201324359개발 환경 구성: 201. Azure Blob Storage의 DNS 경로를 사용자 DNS로 바꾸는 방법 [1]
1512정성태10/18/201327577개발 환경 구성: 200. IIS AppPool의 실행 계정을 변경하는 방법
1511정성태10/12/201325721.NET Framework: 389. The 3n + 1 problem의 C#/Java 버전 풀이 [2]
1510정성태10/8/201326620오류 유형: 190. 윈도우 서버 2012 R2 설치 후 인텔 NIC으로 인한 WMI 오류 발생
1509정성태10/8/201331791오류 유형: 189. Windows Server 8.1/2012 R2 - IME 비정상 종료 현상 [1]
1508정성태10/4/201326865.NET Framework: 388. 일반 닷넷 프로젝트에서 WinRT API를 호출하는 방법 [2]파일 다운로드1
1507정성태9/30/201324727오류 유형: 188. The key 'LocalizedPerfCounter' does not exist in the appSettings configuration section.
1506정성태9/30/201326911오류 유형: 187. Parameter "basePath" cannot be a relative path
1505정성태9/26/201375392기타: 35. Microsoft Office 2007 인증 생략하는 방법 [10]
... 136  137  138  139  140  [141]  142  143  144  145  146  147  148  149  150  ...