Есть ли в кэше функция/метод в С#

Мне стало скучно записывать то же самое в код снова и снова, чтобы кэшировать объекты на уровне доступа к данным.

Есть ли какие-либо функции кэширования функции С# без особых изменений в функциях.

Есть ли какая-либо инфраструктура, поддерживающая эту функцию на данный момент?

Могу ли я архивировать то же самое, написав пользовательские "атрибуты функции С#"? если да, добавьте мне несколько моментов, чтобы начать реализацию?

Ответ 2

Возможность 1: Использовать IL Weaving

Ранее упоминалось сообщение.

Вы также можете попробовать MethodCache.Fody пакет.

Возможность 2: использование прокси/перехвата

Пример (Ninject и Ninject.Interception):

public class CacheAttribute : InterceptAttribute
{
    public override IInterceptor CreateInterceptor(IProxyRequest request)
    {
        return request.Context.Kernel.Get<CachingInterceptor>();
    }
}

public class CachingInterceptor : IInterceptor
{
    private ICache Cache { get; set; }

    public CachingInterceptor(ICache cache)
    {
        Cache = cache;
    }

    public void Intercept(IInvocation invocation)
    {
        string className = invocation.Request.Target.GetType().FullName;
        string methodName = invocation.Request.Method.Name;

        object[] arguments = invocation.Request.Arguments;

        StringBuilder builder = new StringBuilder(100);
        builder.Append(className);
        builder.Append(".");
        builder.Append(methodName);

        arguments.ToList().ForEach(x =>
        {
            builder.Append("_");
            builder.Append(x);
        });

        string cacheKey = builder.ToString();

        object retrieve = Cache.Retrieve<object>(cacheKey);

        if (retrieve == null)
        {
            invocation.Proceed();
            retrieve = invocation.ReturnValue;
            Cache.Store(cacheKey, retrieve);
        }
        else
        {
            invocation.ReturnValue = retrieve;
        }
    }
}

Затем вы можете украсить такие функции:

[Cache]
public virtual Customer GetCustomerByID(int customerID)
{
    return CustomerRepository.GetCustomerByID(customerID);
}

Перехваченные функции должны быть виртуальными, а классы должны быть созданы ядром Ninject. Если вы полагаетесь на производительность, вы можете прокси-классы напрямую через Castle.DynamicProxy(который внутренне используется Ninject.Extensions.Interception.DynamicProxy).

Возможность 3: Использовать оболочку выражения

Вы можете передать функцию как выражение, сгенерировать ключ кеширования, содержащий класс, метод и информацию о параметрах, и вызвать выражение, если оно не найдено в вашем кэше. Это добавляет дополнительные затраты времени на выполнение, чем AOP/Proxy, но будет достаточно для простых решений.

private T CacheAction<T>(Expression<Func<T>> action, [CallerMemberName] string memberName = "") where T : class
{
    MethodCallExpression body = (MethodCallExpression)action.Body;

    ICollection<object> parameters = new List<object>();

    foreach (MemberExpression expression in body.Arguments)
    {
        parameters.Add(((FieldInfo)expression.Member).GetValue(((ConstantExpression)expression.Expression).Value));
    }

    StringBuilder builder = new StringBuilder(100);
    builder.Append(GetType().FullName);
    builder.Append(".");
    builder.Append(memberName);

    parameters.ToList().ForEach(x =>
    {
        builder.Append("_");
        builder.Append(x);
    });

    string cacheKey = builder.ToString();

    T retrieve = Cache.Retrieve<T>(cacheKey);

    if (retrieve == null)
    {
        retrieve = action.Compile().Invoke();
        Cache.Store(cacheKey, retrieve);
    }

    return retrieve;
}

public Customer GetCustomerByID(int customerID)
{
    return CacheAction(() => CustomerRepository.GetCustomerByID(customerID));
}

Ответ 3

Если я правильно прочитал вопрос, правильный термин для вас - memoization. Википедия дает более подробную информацию по этим темам. К сожалению, нет ссылки на библиотеку С#, поддерживающую ее.

Ответ 6

Я предлагаю Spring.Net AOP. Он в основном создает прокси, и вызовы могут быть перенаправлены из/в кеш. http://www.springframework.net/doc/reference/html/aop-quickstart.html

и тогда у вас может быть что-то подобное для вашего совета:

public class CachingAroundAdvice : IMethodInterceptor
{
    #region Variable Declarations
    private Priority priority = Priority.Normal;
    #endregion

    public object Invoke(IMethodInvocation invocation)
    {
        // declare local variables
        string cacheKey = string.Empty;
        object dataObject = null;

        // build cache key with some algorithm
        cacheKey = CreateCacheKey(invocation.Method, invocation.Arguments);

        // retrieve item from cache
        dataObject = CacheManager.Cache.GetData(cacheKey);

        // if the dataobject is not in cache proceed to retrieve it
        if (null == dataObject)
        {
            dataObject = invocation.Proceed();

            // add item to cache
            CacheManager.Cache.Add(cacheKey, dataObject, CachePriority, null, Expiration);
        }

        // return data object
        return dataObject;
    }