C# 13 - (9) 메서드 바인딩의 우선순위를 지정하는 OverloadResolutionPriority 특성 도입 (Overload resolution priority)
이 기능은 현재(2024-10-10) Visual Studio 2022 Preview 버전에서 실습할 수 있습니다.
C# 언어가 지원하는
매개변수의 접근자는 대표적으로 4가지 정도가 됩니다.
이러한 것들은 모두 메서드 시그니처에 반영되고, 그에 따라 메서드를 재정의하는 것이 가능하다 보니 경우에 따라 어떤 메서드가 호출될 것인지 예측하기가 어려워지는 경우도 있습니다. 달리 말하면, C# 컴파일러가 메서드 호출 구문을 분석할 때 실제로 어떤 메서드에 호출을 바인딩해야 하는지 판단하기가 모호할 수 있다는 것입니다.
이런 문제를, C# 13부터는 바인딩 우선순위를 개발자가 직접 OverloadResolutionPriority 특성을 추가해 컴파일러에게 힌트를 제공함으로써 해결할 수 있게 만들었습니다.
Overload resolution priority
; https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-13#overload-resolution-priority
Overload Resolution Priority
; https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-13.0/overload-resolution-priority#overload-resolution-priority
[Proposal]: Overload Resolution Priority (VS 17.12, .NET 9) #7706
; https://github.com/dotnet/csharplang/issues/7706
OverloadResolutionPriority attribute
; https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#overloadresolutionpriority-attribute
System.Runtime.CompilerServices.OverloadResolutionPriority
; https://learn.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.overloadresolutionpriorityattribute
실제로 이 특성을 사용하면 지난 글에 설명한 내용 중,
닷넷: 2291. C# 13 - (5) params 인자 타입으로 컬렉션 허용
; https://www.sysnet.pe.kr/2/0/13705
아래의 코드가 "error CS0121" 컴파일 에러를 발생시키는 것을 해결할 수 있습니다.
// https://www.sysnet.pe.kr/2/0/13705#cs0121
printAll([6, 7, 8, 9, 10]); // 컴파일 에러 - error CS0121: The call is ambiguous between the following methods or properties: 'Program.printAll(List<int>)' and 'Program.printAll(params ReadOnlySpan<int>)'
static void printAll(List<int> args)
{
for (int i = 0; i < args.Count; i++)
{
Console.Write($"{args[i]},");
}
Console.WriteLine();
}
static void printAll(params ReadOnlySpan<int> args)
{
foreach (var item in args)
{
Console.Write($"{item},");
}
Console.WriteLine();
}
지난 글에서는 위의 코드를 컴파일하기 위해 형변환 연산자를 사용했었는데요,
printAll((ReadOnlySpan<int>)[6, 7, 8, 9, 10]); // 컴파일 OK, printAll(params ReadOnlySpan<int> args) 호출로 바인딩
위와 같이 형변환을 하는 대신 OverloadResolutionPriority 특성을 이용해 바인딩 우선순위를 지정하는 것으로 해결할 수도 있습니다.
printAll([6, 7, 8, 9, 10]); // 컴파일 OK, printAll(params ReadOnlySpan<int> args) 호출로 바인딩
static void printAll(List<int> args)
{
Console.Write("List<int> : ");
// ...[생략]...
}
[OverloadResolutionPriority(1)]
static void printAll(params ReadOnlySpan<int> args)
{
Console.Write("ReadOnlySpan<int> : ");
// ...[생략]...
}
물론, "static void printAll(List<int> args)"에 [OverloadResolutionPriority(2)] 특성을 지정하면 이제는 "printAll(List<int> args)" 메서드가 더 높은 우선순위로 바인딩이 됩니다.
참고로, 번호가 클수록 우선순위가 높으며, C# 컴파일러는 OverloadResolutionPriority 특성이 없는 메서드를 "OverloadResolutionPriority(0)"으로 간주합니다.
이 기능은 라이브러리 개발자에게 특히 유용할 수 있습니다. 예를 들어, 위의 예제에서 "printAll(List<int> args)" 구현만을 포함한 v1.0 어셈블리가 있다고 가정해 보겠습니다. 그러다, 좀 더 성능이 좋은 버전인 "ReadOnlySpan<int> args" 인자를 받는 printAll을 추가해 v2.0을 내놓은 경우 기존 v1.0을 사용해 잘 컴파일을 시켰던 "printAll([6, 7, 8, 9, 10])" 코드가 이제는 컴파일 오류로 빌드 실패가 됩니다. 즉, 소스코드 수준에서의 하위 호환성이 깨진 것입니다.
반면, 라이브러리 개발자가 OverloadResolutionPriority 특성을 "ReadOnlySpan<int> args"를 받는 printAll 메서드에 부여하면, v1.0을 사용해 컴파일했던 코드가 v2.0에서도 그대로 컴파일되는 것을 보장할 수 있습니다.
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]