본문 바로가기

C#

C# 메서드 Attribute 기반 캐싱 구현

메서드에 캐싱 기능을 적용할 때, Attribute를 활용하면 코드의 가독성과 재사용성을 높일 수 있습니다. 이번 글에서는 C#에서 Attribute를 이용해 간단한 메서드 캐싱을 구현하는 방법을 소개합니다.

1. 캐시용 Attribute 정의

먼저 캐싱이 적용될 메서드에 사용할 Attribute 클래스를 만듭니다.

[AttributeUsage(AttributeTargets.Method)]
public class CacheAttribute : Attribute
{
    public int DurationSeconds { get; }

    public CacheAttribute(int durationSeconds = 60)
    {
        DurationSeconds = durationSeconds;
    }
}

2. 메서드 캐싱 로직 작성

반복 호출되는 메서드 결과를 저장하는 딕셔너리를 만들고, 캐시 유효 시간을 체크합니다.

using System;
using System.Collections.Concurrent;
using System.Reflection;

public static class CacheManager
{
    private static ConcurrentDictionary _cache 
        = new ConcurrentDictionary<string, (object, DateTime)>();

    public static T GetOrAdd<T>(MethodInfo method, object[] args, Func<T> factory, int duration)
    {
        string key = GetCacheKey(method, args);

        if (_cache.TryGetValue(key, out var cached))
        {
            if (cached.Expiry > DateTime.Now)
                return (T)cached.Value;

            _cache.TryRemove(key, out _);
        }

        T result = factory();
        _cache[key] = (result, DateTime.Now.AddSeconds(duration));
        return result;
    }

    private static string GetCacheKey(MethodInfo method, object[] args)
    {
        string argKey = string.Join("_", args ?? Array.Empty<object>());
        return $"{method.DeclaringType.FullName}.{method.Name}_{argKey}";
    }
}

3. Attribute 적용 및 호출 예시

캐싱 기능을 메서드 호출시 적용하는 예시입니다. 리플렉션과 Delegate를 활용할 수 있습니다.

using System.Reflection;

public class SampleService
{
    [Cache(30)]
    public int Compute(int x, int y)
    {
        Console.WriteLine("실제 메서드 실행");
        return x + y;
    }

    public int ComputeWithCache(int x, int y)
    {
        MethodInfo method = typeof(SampleService).GetMethod(nameof(Compute));
        var attr = method.GetCustomAttribute<CacheAttribute>();

        if (attr == null)
            return Compute(x, y);

        return CacheManager.GetOrAdd(method, new object[] { x, y }, () => Compute(x, y), attr.DurationSeconds);
    }
}

위 예제에서 Compute 메서드는 캐싱이 적용되어 30초 동안 같은 인자값의 결과를 저장합니다. 실제 실행 출력은 첫 호출에만 나타납니다.

4. 마무리

Attribute 기반 캐싱은 코드 중복을 줄이고, 필요한 메서드에 쉽게 적용할 수 있는 방법입니다. 실제 프로젝트에서는 동기화, 캐시 만료, 메모리 관리 등을 추가로 고려해야 합니다.