Мне нужно кэшировать общий список, поэтому мне не нужно запрашивать базу данных несколько раз. В веб-приложении я просто добавлю его в httpcontext.current.cache
. Каким образом можно кэшировать объекты в консольных приложениях?
Кэширование в консольном приложении
Ответ 1
Держите его как экземпляр класса класса. В веб-приложении вы не можете этого сделать, поскольку объект класса страницы воссоздается по каждому запросу.
Однако .NET 4.0 также имеет MemoryCache класс для этой цели.
Ответ 2
В переменной уровня класса. Предположительно, в методе main
вашего консольного приложения вы создаете экземпляр хотя бы одного объекта. В этом классе объектов вы объявляете переменную уровня класса (a List<String>
или что-то еще), в котором вы кешируете все необходимое для кэширования.
Ответ 3
Вот очень простой класс кеша, который я использую в консолях, которые имеют собственную очистку и легкую реализацию.
Использование:
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; }
}
}
}
Ответ 4
// 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?
Ответ 5
Используйте шаблон Singleton.
Ответ 6
Существует множество способов реализации кешей, в зависимости от того, что именно вы делаете. Обычно вы будете использовать словарь для хранения кешированных значений. Вот моя простая реализация кеша, который кэширует значения только в течение ограниченного времени:
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.
Ответ 7
Возможно, вы сможете просто использовать простой словарь. То, что делает кеш настолько особенным в веб-среде, заключается в том, что оно сохраняется и ограничено таким образом, что многие пользователи могут получить к нему доступ. В консольном приложении у вас нет этих проблем. Если ваши потребности достаточно просты, словарь или подобные структуры могут использоваться для быстрого поиска значений, которые вы вытаскиваете из базы данных.