C#에서 Enum 값의 사용자 정의 속성을 효율적으로 접근하기

C#으로 애플리케이션을 개발하는 경우, 때때로 enum 값에 연결된 사용자 정의 속성을 검색해야 할 필요가 발생할 수 있습니다. 이 작업은 특히 반사 및 IL 코드 생성에 익숙하지 않은 경우 겉으로는 간단해 보이지만, enum 값을 문자열(이름)로 변환하는 것만으로는 성능 문제를 초래할 수 있습니다. 이번 블로그 포스트에서는 이러한 속성을 문자열 변환의 번거로움 없이 효율적으로 검색하는 깔끔한 방법을 탐구해 보겠습니다.

문제 이해하기

먼저, 사용자 정의 속성으로 장식된 enum을 정의하는 간단한 예제를 살펴보겠습니다:

public enum MyEnum {
    [CustomInfo("이것은 사용자 정의 속성입니다")]
    None = 0,

    [CustomInfo("이것은 또 다른 속성입니다")]
    ValueA,

    [CustomInfo("이것은 추가 플래그가 있습니다", AllowSomething = true)]
    ValueB,
}

위 코드 조각에서는 여러 값이 포함된 MyEnum이라는 enum을 정의했으며, 각 enum 멤버에 대한 추가 정보가 담긴 CustomInfo 속성이 각 값에 쌍으로 매치됩니다.

도전과제

주요 도전 과제는 enum 인스턴스에서 이러한 CustomInfo 속성을 검색해야 할 때 발생합니다. 가장 먼저 떠오르는 방법은 다음 코드를 사용하는 것입니다:

public CustomInfoAttribute GetInfo(MyEnum enumInput) {
    Type typeOfEnum = enumInput.GetType();
    FieldInfo fi = typeOfEnum.GetField(enumInput.ToString());
    return fi.GetCustomAttributes(typeof(CustomInfoAttribute), false).
        FirstOrDefault() as CustomInfoAttribute;
}

이 함수는 속성을 효과적으로 검색하지만, enumInput.ToString()과 같은 문자열 변환 때문에 성능 비효율을 겪습니다.

더 나은 접근법: IL 코드 생성을 사용하기

다행히도, IL 코드 생성을 통해 enum 값을 문자열로 변환하지 않고 사용자 정의 속성에 접근하는 더 효율적인 방법이 있습니다. 동적 메서드와 ILGenerator를 활용함으로써, 오버헤드를 줄이고 성능을 향상시킬 수 있습니다. 아래에서는 속성에 빠르게 접근할 수 있도록 도와주는 делегейт를 생성하는 방법을 설명합니다. 이 방법은 속성 검색에도 적용할 수 있습니다.

IL 코드 생성을 구현하는 단계

  1. 델리게이트 생성하기: 객체를 입력받고 객체를 반환하는 델리게이트를 정의합니다. 이를 통해 빠른 속성 접근기를 생성할 수 있습니다.

    public delegate object FastPropertyGetHandler(object target);
    
  2. IL 생성하기: ILGenerator를 사용하여 대상 객체를 스택에 로드하고, getter 메서드를 호출하며, 반환값을 처리하는 IL 메서드를 생성합니다.

    private static void EmitBoxIfNeeded(ILGenerator ilGenerator, System.Type type) {
        if (type.IsValueType) {
            ilGenerator.Emit(OpCodes.Box, type);
        }
    }
    
  3. 속성 getter 가져오기: 이제 동적 메서드를 생성하고 빠른 속성 접근기를 만들기 위한 필요한 IL 코드를 빌드하는 방법을 생성합니다:

    public static FastPropertyGetHandler GetPropertyGetter(PropertyInfo propInfo) {
        DynamicMethod dynamicMethod = new DynamicMethod(
            string.Empty, 
            typeof(object), 
            new Type[] { typeof(object) },
            propInfo.DeclaringType.Module);
    
        ILGenerator ilGenerator = dynamicMethod.GetILGenerator();
        ilGenerator.Emit(OpCodes.Ldarg_0);
        ilGenerator.EmitCall(OpCodes.Callvirt, propInfo.GetGetMethod(), null);
        EmitBoxIfNeeded(ilGenerator, propInfo.PropertyType);
        ilGenerator.Emit(OpCodes.Ret);
        FastPropertyGetHandler getter = (FastPropertyGetHandler)dynamicMethod.CreateDelegate(typeof(FastPropertyGetHandler));
        return getter;
    }
    

결론

위에서 설명한 방법을 구현함으로써, enum 값에서 속성을 검색할 때 발생하는 오버헤드를 효과적으로 줄일 수 있습니다. 이 접근법은 불필요한 문자열 변환을 없애고, 성능을 개선하여 효율성을 요구하는 애플리케이션에 필수적입니다.

이러한 기술을 C# 프로젝트에 통합하면 enum 속성을 원활하게 탐색하고, 보다 깔끔하고 유지 관리가 용이한 코드를 작성할 수 있습니다. 코딩 즐겁게 하세요!