Para divertirme, estoy jugando con una clase para almacenar fácilmente los resultados de la función. La idea básica es que puede tomar cualquier función que desee — aunque solo desee usarla para funciones relativamente costosas — y envolverla fácilmente para usar búsquedas de diccionario relativamente económicas para ejecuciones posteriores con el mismo argumento. En realidad no hay mucho que ella:Función de caché resultados
public class AutoCache<TKey, TValue>
{
public AutoCache(Func<TKey, TValue> FunctionToCache)
{
_StoredFunction = FunctionToCache;
_CachedData = new Dictionary<TKey, TValue>();
}
public TValue GetResult(TKey Key)
{
if (!_CachedData.ContainsKey(Key))
_CachedData.Add(Key, _StoredFunction(Key));
return _CachedData[Key];
}
public void InvalidateKey(TKey Key)
{
_CachedData.Remove(Key);
}
public void InvalidateAll()
{
_CachedData.Clear();
}
private Dictionary<TKey, TValue> _CachedData;
private Func<TKey, TValue> _StoredFunction;
}
Por desgracia, hay algunas restricciones adicionales que hacen que esta mucho menos útil de lo que podría ser. También hay algunas características que podríamos agregar y otras consideraciones para la implementación. Estoy buscando ideas sobre maneras en que esto se puede mejorar por cualquiera de los siguientes puntos:
- Esto requiere una función que devuelve el mismo resultado para un conjunto dado de argumentos (que debe ser sin estado). Probablemente no hay forma de cambiar esto.
- Está limitado a un rango delegado muy estrecho. ¿Podríamos expandirlo para que funcione fácilmente para cualquier función que acepte al menos un parámetro y devuelva un valor, tal vez envolviendo argumentos en un tipo anónimo? ¿O necesitaríamos una implementación adicional para cada delegado de Func que quisiéramos apoyar? Si es así, ¿podemos construir una clase abstracta para hacer esto más fácil?
- No es seguro para subprocesos.
- Sin invalidación automática. Esto lo hace peligroso para la recolección de basura. Debes mantenerlo por un tiempo para que sea útil, y eso significa que realmente nunca descartarás elementos de caché viejos y potencialmente innecesarios.
- ¿Podemos heredar esto para hacer que la memoria caché sea bidireccional para el caso en el que la función tiene un único argumento?
Como punto de referencia, si alguna vez uso esto en código real el lugar más probable que visualizo es como parte de una capa de lógica de negocios, donde utilizo este código para ajustar un método en la capa de acceso a datos que simplemente extrae datos de una tabla de búsqueda. En este caso, el viaje de la base de datos sería costoso en relación con el diccionario y casi siempre habría exactamente un valor 'clave' para la búsqueda, por lo que es una buena combinación.
me encanta el curry! – BigBlondeViking
Bien, leeré más sobre Memoization. En este caso, no creo que currying realmente ayude aquí. Sí, hace posible usar este código para manejar una función con múltiples argumentos, pero lo hace de una manera que no es obvia para el usuario de la clase, lo cual derrota el punto de la clase. –