2014-12-09 9 views
8

Ho un servizio di cache come questo:L'accesso a MemoryCache crea una copia?

public interface ICacheService { 
    T Get<T>(string cacheID, Func<T> getItemCallback, int cacheMinutes = 5) where T : class; 
} 

public class MemoryCacheService : ICacheService { 
    public T Get<T>(string cacheId, Func<T> getItemCallback, int cacheMinutes = 5) where T : class { 
     T item = MemoryCache.Default.Get(cacheId) as T; 
     if (item == null) { 
      item = getItemCallback(); 
      MemoryCache.Default.Add(cacheId, item, 
       new CacheItemPolicy {AbsoluteExpiration = DateTime.Now.AddMinutes(cacheMinutes)}); 
     } 
     return item; 
    } 
} 

e recuperati in questo modo:

var result = _cache.Get("mylist",() => _database.Fetch<MyList>().AsQueryable(), 600); 

La lista è grande e vi si accede frequentemente in un menu a discesa per ogni sequenza di tasti di immissione facilitata. E la condizione di query è anche dinamica, come

if (this) result = result.Where(x=> this ...) 
if (that) result = result.Where(x=> that ...) 
finally result.ToList() 

Mi chiedo, ogni volta che accedere alla lista dalla cache, fa il sistema crea una copia dei dati prima di query LINQ edificio di inizio? Se è così, è come la copia per tastiera, non molto efficiente. O lo ha differito la query perché sto recuperando AsQueryable e costruisci linq?

Qualche alternativa migliore? Grazie

risposta

11

No, MemoryCache non esegue una copia. In pratica, si memorizza un riferimento a qualche istanza di oggetto nella cache, e questo è ciò che si ottiene quando si accede a un elemento nella cache.

Non ho un collegamento di documentazione formale, ma ho scoperto la "via difficile" nella pratica, dove ho modificato accidentalmente l'oggetto memorizzato nella cache usando semplicemente il riferimento che ho ricevuto (senza copiarlo).

Inoltre, lo studio delle origini di riferimento (http://referencesource.microsoft.com) indica che non si verifica alcuna copia automatica.

A seconda dell'applicazione e delle esigenze, è possibile assicurarsi che i tipi di cache siano effettivamente immutabili per progettazione.

+0

Ho provato quanto segue per testare quello che hai detto. 'List1 = _cache.Get (...); list1 = list1.Take (2) .ToList(); list2 = _cache.Get (...); 'L'elenco non dovrebbe essere troncato a 2 se fanno riferimento allo stesso oggetto? Ma sembra che abbia ancora l'elenco completo ogni volta. – Whoever

+0

No, perché stai creando una nuova istanza di elenco. Prova a richiamare "Rimuovi" sul riferimento che ottieni dalla cache. –

+0

Ha fatto qualche prova. Sembra che qualsiasi operazione che restituisce una lista crea una copia e modifica il riferimento alla lista1 da quel momento in poi. Non sono sicuro di cosa sia successo a IQueryable ad ogni raffinamento, ma dal momento che non si è materializzato fino alla ToList finale, indovina sto bene. Grazie a tutti i dettagli. – Whoever

4

Senza perdersi nei minimi dettagli di MemoryCache, è possibile ragionare con i principi di progettazione di base di .NET. Solo i tipi di valore sono facili da copiare. Non esiste un meccanismo generale per copiare i tipi di riferimento, oltre a [Serializable] e il molto rotto ICloneable. Quali non sono i requisiti per l'inserimento di un oggetto nel MemoryCache. Quindi no.

Gli oggetti nella cache sono molto, molto semplici. Una semplice lista < ottiene quel lavoro. Il valore aggiunto che si ottiene da MemoryCache è l'altra funzione essenziale di una cache efficace.. Una politica di pensionamento. Una cache senza una politica è una perdita di memoria.

+0

Vuol dire che cache, get e query sono tutti riferimenti alla stessa copia di dati? Sembra avere un senso. E il CacheItemPolicy che ho nel servizio cache, questa è la politica di pensionamento che hai menzionato, giusto? – Whoever

Problemi correlati