using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Caching.Memory; using Newtonsoft.Json; using SqlSugar; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using WIDESEAWCS_Core.Helper; namespace WIDESEAWCS_Core.Caches { public class MemoryCacheService : ICacheService { protected IMemoryCache _cache; public MemoryCacheService(IMemoryCache cache) { _cache = cache; } public bool Add(string key, string value, int expireSeconds = -1, bool isSliding = false) { return AddObject(key, value, expireSeconds, isSliding); } public bool AddObject(string key, object value, int expireSeconds = -1, bool isSliding = false) { if (expireSeconds > 0) { _cache.Set(key, value, new MemoryCacheEntryOptions() .SetSlidingExpiration(new TimeSpan(0, 0, expireSeconds)) ); } else { _cache.Set(key, value); } return true; } public void AddOrUpdate(string key, string value, int expireSeconds = -1, bool isSliding = false) { if (!string.IsNullOrEmpty(Get(key))) { Remove(key); Add(key, value, expireSeconds, isSliding); } else { Add(key, value, expireSeconds, isSliding); } } public void AddOrUpdate(string key, object value, int expireSeconds = -1, bool isSliding = false) { if (!string.IsNullOrEmpty(Get(key))) { Remove(key); Add(key, value.Serialize(), expireSeconds, isSliding); } else { Add(key, value.Serialize(), expireSeconds, isSliding); } } public void Dispose() { if (_cache != null) _cache.Dispose(); GC.SuppressFinalize(this); } public bool Exists(string key) { if (key == null) { throw new ArgumentNullException(nameof(key)); } return _cache.Get(key) != null; } public T? Get(string key) where T : class { if (key == null) { throw new ArgumentNullException(nameof(key)); } object? value = _cache.Get(key); if (value == null) { throw new ArgumentNullException(nameof(key)); } return value as T; } public string? Get(string key) { try { return _cache.Get(key)?.ToString(); } catch { return string.Empty; } } public object? Get(Type type, string key) { try { object res = _cache.Get(key); return res == null ? default : JsonConvert.DeserializeObject(res?.ToString() ?? "{}", type); } catch { return string.Empty; } } public bool Remove(string key) { if (key == null) { throw new ArgumentNullException(nameof(key)); } _cache.Remove(key); return !Exists(key); } public void Remove(IEnumerable keys) { if (keys == null) { throw new ArgumentNullException(nameof(keys)); } keys.ToList().ForEach(item => _cache.Remove(item)); } #region 删除扩展方法 public string? RemoveAndGet(string key) { var value = Get(key); if (value != null) _cache.Remove(key); return value; } public T? RemoveAndGet(string key) where T : class { var value = Get(key); if (value != null) _cache.Remove(key); return value; } public int RemoveByPrefix(string prefix) { if (string.IsNullOrEmpty(prefix)) return 0; // MemoryCache不支持枚举,返回0 return 0; } public int RemoveByPattern(string pattern) { // MemoryCache不支持模式匹配 return 0; } public int RemoveAll(IEnumerable keys) { if (keys == null) return 0; int count = 0; foreach (var key in keys) { if (Remove(key)) count++; } return count; } public int RemoveWhere(Func predicate) { // MemoryCache不支持枚举所有Key return 0; } #endregion #region 添加和修改扩展方法 public void AddAll(IDictionary items, int expireSeconds = -1) { if (items == null) return; foreach (var item in items) { Add(item.Key, item.Value, expireSeconds); } } public void AddAllObjects(IDictionary items, int expireSeconds = -1) { if (items == null) return; foreach (var item in items) { AddObject(item.Key, item.Value, expireSeconds); } } public bool Replace(string key, string newValue, int expireSeconds = -1) { return TryUpdate(key, newValue, expireSeconds); } public bool Replace(string key, T newValue, int expireSeconds = -1) where T : class { if (!Exists(key)) return false; AddObject(key, newValue, expireSeconds); return true; } public string? GetAndRefresh(string key, int expireSeconds) { var value = Get(key); if (value != null) { Add(key, value, expireSeconds); return value; } return null; } public T? GetAndRefresh(string key, int expireSeconds) where T : class { var value = Get(key); if (value != null) { AddObject(key, value, expireSeconds); return value; } return default; } public bool RefreshExpire(string key, int expireSeconds) { var value = Get(key); if (value != null) { Add(key, value, expireSeconds); return true; } return false; } public bool ExpireIn(string key, int seconds) { return RefreshExpire(key, seconds); } public bool ExpireAt(string key, DateTime expireTime) { var seconds = (int)(expireTime - DateTime.Now).TotalSeconds; if (seconds <= 0) return Remove(key); return RefreshExpire(key, seconds); } public long? GetExpire(string key) { return null; // MemoryCache不支持TTL查询 } public bool AddIfNotExists(string key, string value, int expireSeconds = -1) { return TryAdd(key, value, expireSeconds); } public bool AddIfNotExists(string key, T value, int expireSeconds = -1) where T : class { return TryAdd(key, value, expireSeconds); } public string? GetAndSet(string key, string newValue, int expireSeconds = -1) { var oldValue = Get(key); Add(key, newValue, expireSeconds); return oldValue; } public T? GetAndSet(string key, T newValue, int expireSeconds = -1) where T : class { var oldValue = Get(key); AddObject(key, newValue, expireSeconds); return oldValue; } public long Increment(string key, long value = 1) { var current = long.TryParse(Get(key), out var v) ? v : 0; var newValue = current + value; Add(key, newValue.ToString()); return newValue; } public long Decrement(string key, long value = 1) { return Increment(key, -value); } public long Append(string key, string value) { var current = Get(key) ?? ""; var newValue = current + value; Add(key, newValue); return newValue.Length; } #endregion public bool TryAdd(string key, string value, int expireSeconds = -1) { if (Exists(key)) return false; return Add(key, value, expireSeconds); } public bool TryAdd(string key, T value, int expireSeconds = -1) where T : class { if (Exists(key)) return false; return AddObject(key, value, expireSeconds); } public bool TryGetValue(string key, out string? value) { value = _cache.Get(key)?.ToString(); return value != null; } public bool TryGetValue(string key, out T? value) where T : class { if (_cache.TryGetValue(key, out object? obj) && obj != null) { value = obj as T ?? JsonConvert.DeserializeObject(obj.ToString() ?? ""); return value != null; } value = default; return false; } public bool TryRemove(string key, out string? value) { value = _cache.Get(key)?.ToString(); if (value == null) return false; _cache.Remove(key); return true; } public bool TryUpdate(string key, string newValue, int expireSeconds = -1) { if (!Exists(key)) return false; Remove(key); Add(key, newValue, expireSeconds); return true; } public bool TryUpdateIfChanged(string key, string newValue, int expireSeconds = -1) { var existing = Get(key); if (existing == null) return false; if (existing == newValue) return false; // 值相同,不更新 Remove(key); Add(key, newValue, expireSeconds); return true; } public bool TryUpdateIfChanged(string key, T newValue, int expireSeconds = -1) where T : class { var existing = Get(key); if (existing == null) return false; // 使用JSON序列化比较内容,而不是引用比较 var existingJson = JsonConvert.SerializeObject(existing); var newJson = JsonConvert.SerializeObject(newValue); if (existingJson == newJson) return false; // JSON字符串相同,不更新 Remove(key); AddObject(key, newValue, expireSeconds); return true; } public string GetOrAdd(string key, string value, int expireSeconds = -1) { var existing = _cache.Get(key)?.ToString(); if (existing != null) return existing; Add(key, value, expireSeconds); return value; } public string GetOrAdd(string key, Func valueFactory, int expireSeconds = -1) { var existing = _cache.Get(key)?.ToString(); if (existing != null) return existing; var value = valueFactory(key); Add(key, value, expireSeconds); return value; } public T GetOrAdd(string key, Func valueFactory, int expireSeconds = -1) where T : class { if (_cache.TryGetValue(key, out object? obj) && obj != null) { if (obj is T t) return t; var deserialized = JsonConvert.DeserializeObject(obj.ToString() ?? ""); if (deserialized != null) return deserialized; } var value = valueFactory(key); AddObject(key, value, expireSeconds); return value; } } }