Problem

아래와 같이 Reflection을 이용해 호출하는 메소드의 파라미터와 이름을 추출하여 동작하는 코드가 있었다. 관리하지 않은 오래된 코드였고, 최근에 업데이트가 필요한 부분이 생겨 수정되었다. 업데이트 과정에서 알게된 문제로 개발 환경에서는 문제가 없이 잘 동작했지만 라이브 환경에서 실행에 문제가 있었다. 직접적인 에러가 표기되지 않아 로깅을 통해서 라이브 환경에서 디버깅 하였고, 결국 paramNames[index++].Name 부분에서 Name은 항상 Null인 것이 문제임을 확인할 수 있었다. 사용한 코드의 일부는 아래와 같다.

using System.Reflection;

...(중략)

public string GetMemberName<T>(Expression<Func<T>> memberExpression)
{
    MemberExpression expressionBody = (MemberExpression)memberExpression.Body;
    return expressionBody.Member.Name;
}

protected R ContextTemplate<R>(string procedureName, params object[] paramData)
{
    this.connection = new SqlConnection(ConnectionString);

    StackTrace stackTrace = new StackTrace();
    MethodBase methodBase = stackTrace.GetFrame(1).GetMethod();

    var paramNames = methodBase.GetParameters();

    using (connection)
    {
        var param = new DynamicParameters();
        var index = 0;

        foreach (var paramData in paramData)
        {
            param.Add(paramNames[index++].Name, paramData); // 문제 되는 부분
        }

        ...(중략)

        return result.SingleOrDefault();
    }
}

Solution

디버그 모드에서 StackFrame은 작동하지만 코드 최적화 모드가 켜져있는 릴리즈 모드에서는 해당 스택이 예상과 다르게 동작할 수 있었다1. 즉, 이것은 코드 최적화가 되지 않은 빌드에서만 동작하는 코드였던 것이다. 해당 라이브러리의 최적화를 꺼놓은 상태로 빌드해 문제없이 동작하긴 하겠지만, 비슷한 코드를 사용하고 있다면 다른 방법으로 동작하도록 코드를 재작성 하는 것이 좋겠다.

References