Possibilità 1: Utilizzare IL Tessitura
PostSharp è stato menzionato in precedenza.
Si potrebbe anche provare il pacchetto MethodCache.Fody.
Possibilità 2: Utilizzare un/Intercettazione quadro Proxy
Esempio (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;
}
}
}
allora si potrebbe decorare le funzioni in questo modo:
[Cache]
public virtual Customer GetCustomerByID(int customerID)
{
return CustomerRepository.GetCustomerByID(customerID);
}
Le funzioni intercettate devono essere virtuali e le classi devono essere create dal kernel di Ninject. Se si fa affidamento sulle prestazioni, è possibile eseguire il proxy delle classi direttamente tramite Castle.DynamicProxy (che viene utilizzato internamente da Ninject.Extensions.Interception.DynamicProxy).
Possibilità 3: Utilizzare un involucro Espressione
Si potrebbe passare la funzione di espressione, generare una chiave di cache contenente classe, metodo e sui parametri e richiamare l'espressione, se non si trova nella cache. Ciò aggiunge un sovraccarico di runtime maggiore rispetto ai framework AOP/Proxy, ma sarà sufficiente per soluzioni semplici.
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));
}
"Mi sono stancato di scrivere lo stesso codice per eseguire più e più volte nella cache gli oggetti nel livello di accesso ai dati." - Ereditarietà forse? –
non ereditarietà, non si desidera scrivere codice ridondante per verificare se l'oggetto cache esiste o no? e quindi effettuare una chiamata a un oggetto reale o prendere dalla cache. In qualsiasi modo "Yuriy Faktorovich" si è rivolto a tutti. Questo è quello che sto cercando esattamente – Veeru