Ответ 1
Держите его как экземпляр класса класса. В веб-приложении вы не можете этого сделать, поскольку объект класса страницы воссоздается по каждому запросу.
Однако .NET 4.0 также имеет MemoryCache класс для этой цели.
Мне нужно кэшировать общий список, поэтому мне не нужно запрашивать базу данных несколько раз. В веб-приложении я просто добавлю его в httpcontext.current.cache
. Каким образом можно кэшировать объекты в консольных приложениях?
Держите его как экземпляр класса класса. В веб-приложении вы не можете этого сделать, поскольку объект класса страницы воссоздается по каждому запросу.
Однако .NET 4.0 также имеет MemoryCache класс для этой цели.
В переменной уровня класса. Предположительно, в методе main
вашего консольного приложения вы создаете экземпляр хотя бы одного объекта. В этом классе объектов вы объявляете переменную уровня класса (a List<String>
или что-то еще), в котором вы кешируете все необходимое для кэширования.
Вот очень простой класс кеша, который я использую в консолях, которые имеют собственную очистку и легкую реализацию.
Использование:
return Cache.Get("MyCacheKey", 30, () => { return new Model.Guide().ChannelListings.BuildChannelList(); });
Класс:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Timers;
namespace MyAppNamespace
{
public static class Cache
{
private static Timer cleanupTimer = new Timer() { AutoReset = true, Enabled = true, Interval = 60000 };
private static readonly Dictionary<string, CacheItem> internalCache = new Dictionary<string, CacheItem>();
static Cache()
{
cleanupTimer.Elapsed += Clean;
cleanupTimer.Start();
}
private static void Clean(object sender, ElapsedEventArgs e)
{
internalCache.Keys.ToList().ForEach(x => { try { if (internalCache[x].ExpireTime <= e.SignalTime) { Remove(x); } } catch (Exception) { /*swallow it*/ } });
}
public static T Get<T>(string key, int expiresMinutes, Func<T> refreshFunction)
{
if (internalCache.ContainsKey(key) && internalCache[key].ExpireTime > DateTime.Now)
{
return (T)internalCache[key].Item;
}
var result = refreshFunction();
Set(key, result, expiresMinutes);
return result;
}
public static void Set(string key, object item, int expiresMinutes)
{
Remove(key);
internalCache.Add(key, new CacheItem(item, expiresMinutes));
}
public static void Remove(string key)
{
if (internalCache.ContainsKey(key))
{
internalCache.Remove(key);
}
}
private struct CacheItem
{
public CacheItem(object item, int expiresMinutes)
: this()
{
Item = item;
ExpireTime = DateTime.Now.AddMinutes(expiresMinutes);
}
public object Item { get; private set; }
public DateTime ExpireTime { get; private set; }
}
}
}
// Consider this psuedo code for using Cache
public DataSet GetMySearchData(string search)
{
// if it is in my cache already (notice search criteria is the cache key)
string cacheKey = "Search " + search;
if (Cache[cacheKey] != null)
{
return (DataSet)(Cache[cacheKey]);
}
else
{
DataSet result = yourDAL.DoSearch(search);
Cache[cacheKey].Insert(result); // There are more params needed here...
return result;
}
}
Ref: Как кэшировать набор данных для остановки маршрутов в db?
Используйте шаблон Singleton.
Существует множество способов реализации кешей, в зависимости от того, что именно вы делаете. Обычно вы будете использовать словарь для хранения кешированных значений. Вот моя простая реализация кеша, который кэширует значения только в течение ограниченного времени:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CySoft.Collections
{
public class Cache<TKey,TValue>
{
private readonly Dictionary<TKey, CacheItem> _cache = new Dictionary<TKey, CacheItem>();
private TimeSpan _maxCachingTime;
/// <summary>
/// Creates a cache which holds the cached values for an infinite time.
/// </summary>
public Cache()
: this(TimeSpan.MaxValue)
{
}
/// <summary>
/// Creates a cache which holds the cached values for a limited time only.
/// </summary>
/// <param name="maxCachingTime">Maximum time for which the a value is to be hold in the cache.</param>
public Cache(TimeSpan maxCachingTime)
{
_maxCachingTime = maxCachingTime;
}
/// <summary>
/// Tries to get a value from the cache. If the cache contains the value and the maximum caching time is
/// not exceeded (if any is defined), then the cached value is returned, else a new value is created.
/// </summary>
/// <param name="key">Key of the value to get.</param>
/// <param name="createValue">Function creating a new value.</param>
/// <returns>A cached or a new value.</returns>
public TValue Get(TKey key, Func<TValue> createValue)
{
CacheItem cacheItem;
if (_cache.TryGetValue(key, out cacheItem) && (DateTime.Now - cacheItem.CacheTime) <= _maxCachingTime) {
return cacheItem.Item;
}
TValue value = createValue();
_cache[key] = new CacheItem(value);
return value;
}
private struct CacheItem
{
public CacheItem(TValue item)
: this()
{
Item = item;
CacheTime = DateTime.Now;
}
public TValue Item { get; private set; }
public DateTime CacheTime { get; private set; }
}
}
}
Вы можете передать выражение лямбда методу Get, который, например, извлекает значения из db.
Возможно, вы сможете просто использовать простой словарь. То, что делает кеш настолько особенным в веб-среде, заключается в том, что оно сохраняется и ограничено таким образом, что многие пользователи могут получить к нему доступ. В консольном приложении у вас нет этих проблем. Если ваши потребности достаточно просты, словарь или подобные структуры могут использоваться для быстрого поиска значений, которые вы вытаскиваете из базы данных.