2011-02-08 10 views
11

Mi sono stufato di scrivere lo stesso codice in più e più volte per memorizzare nella cache gli oggetti nel livello di accesso ai dati.Esiste comunque un modo per memorizzare la funzione/metodo in C#

Esiste comunque un modo per memorizzare i risultati della funzione C# senza apportare molte modifiche alle funzioni.

C'è qualche struttura supporta questa funzionalità al momento?

Posso archiviare lo stesso scrivendo personalizzato "attributi di funzione C#"? se sì, mi lasci qualche punto per iniziare l'implementazione?

+3

"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? –

+0

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

risposta

7

È possibile creare attributi di memorizzazione nella cache con PostSharp. Here è un esempio.

+0

Grazie, questo è esattamente quello che sto cercando – Veeru

2

Cache Application block è la risposta di Microsoft alla libreria incorporata per la memorizzazione nella cache in .NET.

+0

Si noti che a partire dalla Enterprise Library 6, il blocco è stato ritirato (vedere http://msdn.microsoft.com/en-us/library/dn169621.aspx). Questo è comprensibile in quanto la funzionalità può essere trovata in System.Runtime.Caching da .NET 4.0 (vedere http://msdn.microsoft.com/en-us/library/system.runtime.caching(v=vs.100).aspx). – Philippe

0

Suggerisco Spring.Net AOP. Fondamentalmente crea un proxy e le chiamate possono essere reindirizzate da/verso la cache. http://www.springframework.net/doc/reference/html/aop-quickstart.html

e quindi si può avere una cosa del genere per il vostro consiglio:

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; 
    } 
3

Se leggo si domanda corretta, il termine giusto per ciò che si vuole è memoization. Wikipedia fornisce maggiori dettagli su questo argomento. Sfortunatamente non ci sono riferimenti a una libreria C# che la supporta.

+0

http://code.google.com/p/mbcache – Roger

18

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)); 
} 
Problemi correlati