Cómo borrar MemoryCache?

He creado un caché usando la clase MemoryCache. Le agrego algunos elementos, pero cuando necesito volver a cargar el caché, quiero borrarlo primero. ¿Cuál es la forma más rápida de hacer esto? ¿Debería recorrer todos los elementos y eliminarlos uno a la vez o hay una forma mejor?

Dispose el MemoryCache existente y cree un nuevo objeto MemoryCache.

El problema con la enumeración

La sección Observaciones de MemoryCache.GetEnumerator () advierte: “Recuperar un enumerador para una instancia de MemoryCache es una operación de uso intensivo y de locking. Por lo tanto, el enumerador no se debe usar en aplicaciones de producción”.

Este es el motivo , explicado en el pseudocódigo de la implementación de GetEnumerator ():

 Create a new Dictionary object (let's call it AllCache) For Each per-processor segment in the cache (one Dictionary object per processor) { Lock the segment/Dictionary (using lock construct) Iterate through the segment/Dictionary and add each name/value pair one-by-one to the AllCache Dictionary (using references to the original MemoryCacheKey and MemoryCacheEntry objects) } Create and return an enumerator on the AllCache Dictionary 

Dado que la implementación divide el caché en varios objetos del diccionario, debe reunir todo en una sola colección para devolver un enumerador. Cada llamada a GetEnumerator ejecuta el proceso de copia completo detallado anteriormente. El diccionario creado recientemente contiene referencias a la clave interna original y los objetos de valor, por lo que sus valores de datos en caché no se duplican.

La advertencia en la documentación es correcta. Evite GetEnumerator (), incluidas todas las respuestas anteriores que utilizan consultas LINQ.

Una solución mejor y más flexible

Aquí hay una forma eficiente de borrar el caché que simplemente se basa en la infraestructura de monitoreo de cambios existente. También proporciona la flexibilidad para borrar todo el caché o solo un subconjunto con nombre y no tiene ninguno de los problemas mencionados anteriormente.

 // By Thomas F. Abraham (http://www.tfabraham.com) namespace CacheTest { using System; using System.Diagnostics; using System.Globalization; using System.Runtime.Caching; public class SignaledChangeEventArgs : EventArgs { public string Name { get; private set; } public SignaledChangeEventArgs(string name = null) { this.Name = name; } } ///  /// Cache change monitor that allows an app to fire a change notification /// to all associated cache items. ///  public class SignaledChangeMonitor : ChangeMonitor { // Shared across all SignaledChangeMonitors in the AppDomain private static event EventHandler Signaled; private string _name; private string _uniqueId = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture); public override string UniqueId { get { return _uniqueId; } } public SignaledChangeMonitor(string name = null) { _name = name; // Register instance with the shared event SignaledChangeMonitor.Signaled += OnSignalRaised; base.InitializationComplete(); } public static void Signal(string name = null) { if (Signaled != null) { // Raise shared event to notify all subscribers Signaled(null, new SignaledChangeEventArgs(name)); } } protected override void Dispose(bool disposing) { SignaledChangeMonitor.Signaled -= OnSignalRaised; } private void OnSignalRaised(object sender, SignaledChangeEventArgs e) { if (string.IsNullOrWhiteSpace(e.Name) || string.Compare(e.Name, _name, true) == 0) { Debug.WriteLine( _uniqueId + " notifying cache of change.", "SignaledChangeMonitor"); // Cache objects are obligated to remove entry upon change notification. base.OnChanged(null); } } } public static class CacheTester { public static void TestCache() { MemoryCache cache = MemoryCache.Default; // Add data to cache for (int idx = 0; idx < 50; idx++) { cache.Add("Key" + idx.ToString(), "Value" + idx.ToString(), GetPolicy(idx)); } // Flush cached items associated with "NamedData" change monitors SignaledChangeMonitor.Signal("NamedData"); // Flush all cached items SignaledChangeMonitor.Signal(); } private static CacheItemPolicy GetPolicy(int idx) { string name = (idx % 2 == 0) ? null : "NamedData"; CacheItemPolicy cip = new CacheItemPolicy(); cip.AbsoluteExpiration = System.DateTimeOffset.UtcNow.AddHours(1); cip.ChangeMonitors.Add(new SignaledChangeMonitor(name)); return cip; } } } 

Desde http://connect.microsoft.com/VisualStudio/feedback/details/723620/memorycache-class-needs-a-clear-method

La solución alternativa es:

 List cacheKeys = MemoryCache.Default.Select(kvp => kvp.Key).ToList(); foreach (string cacheKey in cacheKeys) { MemoryCache.Default.Remove(cacheKey); } 
 var cacheItems = cache.ToList(); foreach (KeyValuePair a in cacheItems) { cache.Remove(a.Key); } 

Si el rendimiento no es un problema, entonces este buen one-liner hará el truco:

 cache.ToList().ForEach(a => cache.Remove(a.Key)); 

Parece que hay un método Trim .

Entonces, para borrar todo lo que harías

 cache.Trim(100) 

EDITAR: después de cavar un poco más, parece que mirar en Trim no vale su tiempo

https://connect.microsoft.com/VisualStudio/feedback/details/831755/memorycache-trim-method-doesnt-evict-100-of-the-items

¿Cómo borro un System.Runtime.Caching.MemoryCache?

También podrías hacer algo como esto:

 Dim _Qry = (From n In CacheObject.AsParallel() Select n).ToList() For Each i In _Qry CacheObject.Remove(i.Key) Next 

Me encontré con esto y, basado en él, escribí un método claro paralelo más ligero:

  public void ClearAll() { var allKeys = _cache.Select(o => o.Key); Parallel.ForEach(allKeys, key => _cache.Remove(key)); } 

una versión mejorada de la respuesta de magritte.

 var cacheKeys = MemoryCache.Default.Where(kvp.Value is MyType).Select(kvp => kvp.Key).ToList(); foreach (string cacheKey in cacheKeys) { MemoryCache.Default.Remove(cacheKey); }