Ответ 1
Вы можете создавать атрибуты кеширования с помощью PostSharp. Вот пример.
Мне стало скучно записывать то же самое в код снова и снова, чтобы кэшировать объекты на уровне доступа к данным.
Есть ли какие-либо функции кэширования функции С# без особых изменений в функциях.
Есть ли какая-либо инфраструктура, поддерживающая эту функцию на данный момент?
Могу ли я архивировать то же самое, написав пользовательские "атрибуты функции С#"? если да, добавьте мне несколько моментов, чтобы начать реализацию?
Вы можете создавать атрибуты кеширования с помощью PostSharp. Вот пример.
Возможность 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));
}
Если я правильно прочитал вопрос, правильный термин для вас - memoization. Википедия дает более подробную информацию по этим темам. К сожалению, нет ссылки на библиотеку С#, поддерживающую ее.
Блок кэша приложений - ответ Microsoft на встроенную библиотеку для кэширования в .NET.
Lazy сохраняет значение после первого запуска. Пример: http://msdn.microsoft.com/en-us/vstudio/bb870976
Я предлагаю 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;
}