프로그래밍을 하다보면 결과나 상태를 확인해야할 때가 많습니다.

디버깅 시에 호출 스택(Call stack)을 살펴보는 방법이나 지역 변수, 컨텍스트 등을 확인하는 것 또한 많은 도움이 됩니다.

하지만, 스레드가 작업을 하는 경우는 이야기가 달라집니다. 호출 스택에선 볼 수가 없더군요 - _-;;

그리고 작업 도중에 디버그를 할 경우에 외관을 볼 수 없는 윈도우 어플리케이션 같은... (메세지 처리가 중단됩니다) 까다로운 녀석들을 상대로도, 게임 프로그래밍을 할 때도 마찬가지입니다.


이럴 땐, System.Diagnostics 네임스페이스에 있는 Debug 클래스의 Print 메서드를 사용하여 출력 창에 찍는 방법이 있습니다.

출력 창에 로그를 남기는 것은 .NET의 강점이라고 볼 수 있을만큼 유용하게 사용됩니다.

이 메서드를 어떻게 사용하느냐에 따라 유용하고, 속도 저하의 원인이 되는지가 갈리게 됩니다.


호출되고 있는 메서드를 보려면 MethodBase 클래스의 정적 메서드인 GetCurrentMethod() 를 사용해도 되지만, StackTrace 클래스 및 StackFrame 클래스를 사용해도 가능합니다. 하지만, 이번 글에선 현재 호출되고 있는 메서드의 이름만 구할 것이기 때문에 간단하게 MethodBase 클래스의 GetCurrentMethod() 를 살펴보도록 하겠습니다.

public static MethodBase GetCurrentMethod();


MethodBase를 반환하게 되어있네요. (MethodBase 클래스 참조 문서, MSDN)

(MethodBase.GetCurrentMethod().GetCurrentMethod().GetCurrentMethod() .....ㅋㅋㅋㅋㅋㅋㅋㅋㅋ)

그리고 GetCurrentMethod() 에 대한 문서도 링크를 해야겠죠?

(GetCurrentMethod 메서드 참조 문서, MSDN)


MSDN의 문서에도 친히 '현재 실행하고 있는 메서드를 나타내는 MethodBase 개체를 반환합니다.' 라고 설명하고 있습니다. 그럼 저 개체를 가지고 어떻게 이름을 가져오느냐? 방법은 매우 간단합니다. MethodBase 클래스의 Name 속성을 이용하는 것. 그게 끝입니다.


그럼 실 사용 예를 한번 보도록 하겠습니다.

using System;
using System.Reflection;
namespace CSharpRef {
    class Program {
        public static void Main(string[] args) {
            MethodBase ctxMethod = MethodBase.GetCurrentMethod();
            Console.WriteLine("Current Method Information:");
            Console.WriteLine("  Name         : {0}", ctxMethod.Name);
            Console.WriteLine("  FullName     : {0}.{1}", ctxMethod.ReflectedType.FullName, ctxMethod.Name);
            Console.WriteLine("  Static Method: {0}", ctxMethod.IsStatic);
            Console.WriteLine("  Public Method: {0}", ctxMethod.IsPublic);
            Console.ReadKey(true);
        }
    }
}



예제 코드의 실행 결과입니다.

메서드의 이름이나 한정자가 맞게 나온 것을 확인하실 수 있습니다.

IsPrivate, IsFinal, IsAbstract 등등 다양한 속성들이 지원되기도 합니다.

정말로 메서드의 대한 전반적인 정보를 가지고 있기 때문에 이걸 응용하여 로깅을 더 확실하게 할 수 있게 됩니다.

예를 들면, 로깅을 할 때 메서드의 위치까지 출력하는 것입니다.

public static void PrintEx(String text, MethodBase loc) {
    Debug.Print("{0}.{1} - {2}", loc.ReflectedType.FullName, loc.Name, text);
}


이런 식으로 코딩을 하고, 로깅이 이뤄지는 메서드에서는 선행 작업으로 GetCurrentMethod 메서드를 이용하여 현재 메서드의 정보를 받아온 후에 PrintEx 메서드의 매개 변수로 넘겨주기만 하면 되겠지요.

(StackTrace 및 StackFrame 클래스를 이용하면 선행 작업 없이도 호출 중인 메서드를 가져오는 것이 가능하지만, 이 글의 주제와는 맞지 않으므로 설명을 하지 않겠습니다)


로깅이 얼마나 효율적으로 변했는지 아래와 같은 코드 작성 후 직접 테스트해보았습니다.

public static void WhatIsWrongInThisMethod() {
    MethodBase cmb = MethodBase.GetCurrentMethod();
    try {
        Int32 a = 100;
        Int32 b = 0;
        Int32 c = a / b;
    } catch (Exception ex) {
        PrintEx(ex.Message, cmb);
    }
}


실행 결과입니다. 메서드의 위치가 표시되고 예외의 내용도 같이 표시가 되는 것을 볼 수가 있습니다.


이 처럼, 아주 간단한 방법으로 강력한 기능을 가진 로깅을 적용할 수 있습니다.

그리고, System.Reflection 네임스페이스에는 메서드, 모듈, 형식 등을 다루고 관리하는데에 필요한 클래스들이 모여있습니다.

추가로 MSIL(Microsoft Intermediate Language, 마이크로소프트 공통 언어)를 프로그래밍하는 것 또한 가능합니다.

관심있으신 분들은 자세히 살펴보는 것도 많은 공부가 될 거라 생각합니다.



긴 글 읽어주셔서 감사합니다!

+ Recent posts