C# 5의 Caller Info를 .NET 4.5 미만의 응용 프로그램에 적용하는 방법
CallerInfo에 대해 예전에 한번 소개해 드렸는데요.
C# 5.0 에 새로 추가된 Caller Info 특성
; https://www.sysnet.pe.kr/2/0/1134
C# 코드 구문으로는 다음과 같이 사용하지만,
public static class MyExt
{
public static void Write(string msg, [CallerMemberName] string method = "")
{
Console.WriteLine(string.Format("{0}:{1}", method, msg));
}
public void Test()
{
MyExt.Write("test");
}
}
C# 컴파일러는 결국 다음과 같은 식으로 변환해서 컴파일하는 것에 불과합니다.
public static class MyExt
{
public static void Write(string msg, [CallerMemberName] string method)
{
Console.WriteLine(string.Format("{0}:{1}", method, msg));
}
public void MyMethod()
{
MyExt.Write("test", "MyMethod");
}
}
변환된 이 코드는, C# 5 버전과 아무런 종속 관계가 없습니다. 그래서, Caller Info를 사용한 코드가 담긴 프로젝트의 "TargetFramework" 속성을 ".NET 3.5"로 바꿔 컴파일해도 생성된 바이너리는 정상적으로 CLR 2 기반에서 잘 동작합니다.
단지, .NET 4.0 이하의 경우 mscorlib.dll에 CallerMemberNameAttribute 타입이 정의되어 있지 않기 때문에 빌드 에러를 피하기 위해 다음과 같이 임의로 만들어 포함해야 합니다.
namespace System.Runtime.CompilerServices
{
using System;
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
public sealed class CallerMemberNameAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
public class CallerFilePathAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
public class CallerLineNumberAttribute : Attribute
{
}
}
public static class MyExt
{
public static void Write(string msg, [CallerMemberName] string method = "")
{
Console.WriteLine(string.Format("{0}:{1}", method, msg));
}
public void MyMethod()
{
MyExt.Write("test", "MyMethod");
}
}
이런 내용들이 다음의 글에 잘 포함되어 있습니다.
Using C# 5 caller info attributes when targeting earlier versions of the .NET framework
; http://www.thomaslevesque.com/2012/06/13/using-c-5-caller-info-attributes-when-targeting-earlier-versions-of-the-net-framework/
그런데, 같은 소스 코드를 닷넷 버전별로 컴파일하고 싶다면 어떻게 해야 할까요? 이런 경우 전처리기 지시자를 사용하면 됩니다. 가령 다음과 같은 식입니다.
using System;
using System.Runtime.CompilerServices;
#if BELOW45
namespace System.Runtime.CompilerServices
{
using System;
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
public sealed class CallerMemberNameAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
public class CallerFilePathAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
public class CallerLineNumberAttribute : Attribute
{
}
}
#endif
class NormalProgram
{
static void Main(string[] args)
{
// ...[생략]...
}
}
.NET 2.0 ~ 4로 컴파일할 땐 BELOW45 상수를 정의하고 4.5 이상인 경우에는 상수 정의를 없애주면 됩니다. msbuild.exe로 빌드한다면 다음과 같이 나눠서 빌드하면 됩니다.
// ---------------------------- C# 5.0 컴파일러로 2가지 상황에 따라 빌드
// .NET 2.0 ~ 4.0
msbuild MyTest.csproj /p:DefineConstants="BELOW45;TRACE" /t:Rebuild /p:TargetFrameworkVersion=v3.5
// .NET 4.5 or later
msbuild MyTest.csproj /t:Rebuild
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]