diff --git a/NewLife.Core/Caching/MemoryCache.cs b/NewLife.Core/Caching/MemoryCache.cs index 3973ac016..70a4a631d 100644 --- a/NewLife.Core/Caching/MemoryCache.cs +++ b/NewLife.Core/Caching/MemoryCache.cs @@ -95,7 +95,7 @@ public override void Init(String? config) { if (_cache.TryGetValue(key, out item) && item != null) { - if (!item.Expired) return (T?)item.Visit(); + if (!item.Expired) return item.Visit(); item.Set(value, expire); @@ -107,7 +107,7 @@ public override void Init(String? config) Interlocked.Increment(ref _count); - return (T?)item.Visit(); + return item.Visit(); } #endregion @@ -163,11 +163,7 @@ public override T Get(String key) { if (!_cache.TryGetValue(key, out var item) || item == null || item.Expired) return default; - var rs = item.Visit(); - if (rs == null) return default; - if (rs is T t) return t; - - return rs.ChangeType(); + return item.Visit(); } /// 移除缓存项 @@ -220,7 +216,7 @@ public override Boolean SetExpire(String key, TimeSpan expire) { if (!_cache.TryGetValue(key, out var item) || item == null) return false; - item.Set(item.Value, expire); + item.SetExpire(expire); return true; } @@ -282,7 +278,7 @@ public override T Replace(String key, T value) { if (_cache.TryGetValue(key, out item) && item != null) { - var rs = item.Value; + var rs = item.Visit(); // 如果已经过期,不要返回旧值 if (item.Expired) rs = default(T); @@ -315,7 +311,7 @@ public override Boolean TryGetValue(String key, [MaybeNullWhen(false)] out T if (!_cache.TryGetValue(key, out var item) || item == null) return false; // 得到已有值 - value = item.Visit().ChangeType(); + value = item.Visit(); // 是否未过期的有效值 return !item.Expired; @@ -335,14 +331,14 @@ public override T GetOrAdd(String key, Func callback, Int32 expire CacheItem? item = null; do { - if (_cache.TryGetValue(key, out item) && item != null) return (T?)item.Visit(); + if (_cache.TryGetValue(key, out item) && item != null) return item.Visit(); item ??= new CacheItem(callback(key), expire); } while (!_cache.TryAdd(key, item)); Interlocked.Increment(ref _count); - return (T?)item.Visit(); + return item.Visit(); } /// 累加,原子操作 @@ -394,8 +390,8 @@ public override Double Decrement(String key, Double value) public override IList GetList(String key) { var item = GetOrAddItem(key, k => new List()); - return item.Visit() as IList ?? - throw new InvalidCastException($"Unable to convert the value of [{key}] from {item.Value?.GetType()} to {typeof(IList)}"); + return item.Visit>() ?? + throw new InvalidCastException($"Unable to convert the value of [{key}] from {item.TypeCode} to {typeof(IList)}"); } /// 获取哈希 @@ -405,8 +401,8 @@ public override IList GetList(String key) public override IDictionary GetDictionary(String key) { var item = GetOrAddItem(key, k => new ConcurrentDictionary()); - return item.Visit() as IDictionary ?? - throw new InvalidCastException($"Unable to convert the value of [{key}] from {item.Value?.GetType()} to {typeof(IDictionary)}"); + return item.Visit>() ?? + throw new InvalidCastException($"Unable to convert the value of [{key}] from {item.TypeCode} to {typeof(IDictionary)}"); } /// 获取队列 @@ -416,8 +412,8 @@ public override IDictionary GetDictionary(String key) public override IProducerConsumer GetQueue(String key) { var item = GetOrAddItem(key, k => new MemoryQueue()); - return item.Visit() as IProducerConsumer ?? - throw new InvalidCastException($"Unable to convert the value of [{key}] from {item.Value?.GetType()} to {typeof(IProducerConsumer)}"); + return item.Visit>() ?? + throw new InvalidCastException($"Unable to convert the value of [{key}] from {item.TypeCode} to {typeof(IProducerConsumer)}"); } /// 获取栈 @@ -427,8 +423,8 @@ public override IProducerConsumer GetQueue(String key) public override IProducerConsumer GetStack(String key) { var item = GetOrAddItem(key, k => new MemoryQueue(new ConcurrentStack())); - return item.Visit() as IProducerConsumer ?? - throw new InvalidCastException($"Unable to convert the value of [{key}] from {item.Value?.GetType()} to {typeof(IProducerConsumer)}"); + return item.Visit>() ?? + throw new InvalidCastException($"Unable to convert the value of [{key}] from {item.TypeCode} to {typeof(IProducerConsumer)}"); } /// 获取Set @@ -439,8 +435,8 @@ public override IProducerConsumer GetStack(String key) public override ICollection GetSet(String key) { var item = GetOrAddItem(key, k => new HashSet()); - return item.Visit() as ICollection ?? - throw new InvalidCastException($"Unable to convert the value of [{key}] from {item.Value?.GetType()} to {typeof(ICollection)}"); + return item.Visit>() ?? + throw new InvalidCastException($"Unable to convert the value of [{key}] from {item.TypeCode} to {typeof(ICollection)}"); } /// 获取 或 添加 缓存项 @@ -476,11 +472,15 @@ protected CacheItem GetOrAddItem(String key, Func valueFactory) /// 缓存项 protected class CacheItem { - private Object? _Value; + /// 数值类型 + public TypeCode TypeCode { get; set; } + + private Int64 _valueLong; + private Object? _value; /// 数值 - public Object? Value { get => _Value; set => _Value = value; } + public Object? Value { get => IsInt() ? _valueLong : _value; } - /// 过期时间 + /// 过期时间。系统启动以来的毫秒数 public Int64 ExpiredTime { get; set; } /// 是否过期 @@ -497,24 +497,28 @@ protected class CacheItem /// 设置数值和过期时间 /// /// 过期时间,秒 - public void Set(Object? value, Int32 expire) - { - Value = value; - - var now = VisitTime = Runtime.TickCount64; - if (expire <= 0) - ExpiredTime = Int64.MaxValue; - else - ExpiredTime = now + expire * 1000L; - } + public void Set(T value, Int32 expire) => Set(value, TimeSpan.FromSeconds(expire)); /// 设置数值和过期时间 /// /// 过期时间,秒 - public void Set(Object? value, TimeSpan expire) + public void Set(T value, TimeSpan expire) { - Value = value; + var type = typeof(T); + TypeCode = type.GetTypeCode(); + + if (IsInt()) + _valueLong = value.ToLong(); + else + _value = value; + SetExpire(expire); + } + + /// 设置过期时间 + /// + public void SetExpire(TimeSpan expire) + { var now = VisitTime = Runtime.TickCount64; if (expire == TimeSpan.Zero) ExpiredTime = Int64.MaxValue; @@ -522,12 +526,35 @@ public void Set(Object? value, TimeSpan expire) ExpiredTime = now + (Int64)expire.TotalMilliseconds; } + private Boolean IsInt() => TypeCode >= TypeCode.SByte && TypeCode <= TypeCode.UInt64; + //private Boolean IsDouble() => TypeCode is TypeCode.Single or TypeCode.Double or TypeCode.Decimal; + /// 更新访问时间并返回数值 /// - public Object? Visit() + public T? Visit() { VisitTime = Runtime.TickCount64; - return Value; + + if (IsInt()) + { + // 存入取出相同,大多数时候走这里 + if (_valueLong is T n) return n; + + return _valueLong.ChangeType(); + } + else + { + var rs = _value; + if (rs == null) return default; + + // 存入取出相同,大多数时候走这里 + if (rs is T t) return t; + + // 复杂类型返回空值,避免ChangeType失败抛出异常 + if (typeof(T).GetTypeCode() == TypeCode.Object) return default; + + return rs.ChangeType(); + } } /// 递增 @@ -535,16 +562,17 @@ public void Set(Object? value, TimeSpan expire) /// public Int64 Inc(Int64 value) { - // 原子操作 - Int64 newValue; - Object oldValue; - do + // 如果不是整数,先转为整数 + if (!IsInt()) { - oldValue = _Value ?? 0L; - newValue = (oldValue is Int64 n ? n : oldValue.ToLong()) + value; - } while (Interlocked.CompareExchange(ref _Value, newValue, oldValue) != oldValue); + _valueLong = _value.ToLong(); + TypeCode = TypeCode.Int64; + } - Visit(); + // 原子操作 + var newValue = Interlocked.Add(ref _valueLong, value); + + VisitTime = Runtime.TickCount64; return newValue; } @@ -556,14 +584,14 @@ public Double Inc(Double value) { // 原子操作 Double newValue; - Object oldValue; + Object? oldValue; do { - oldValue = _Value ?? 0d; + oldValue = _value; newValue = (oldValue is Double n ? n : oldValue.ToDouble()) + value; - } while (Interlocked.CompareExchange(ref _Value, newValue, oldValue) != oldValue); + } while (Interlocked.CompareExchange(ref _value, newValue, oldValue) != oldValue); - Visit(); + VisitTime = Runtime.TickCount64; return newValue; } @@ -573,16 +601,17 @@ public Double Inc(Double value) /// public Int64 Dec(Int64 value) { - // 原子操作 - Int64 newValue; - Object oldValue; - do + // 如果不是整数,先转为整数 + if (!IsInt()) { - oldValue = _Value ?? 0L; - newValue = (oldValue is Int64 n ? n : oldValue.ToLong()) - value; - } while (Interlocked.CompareExchange(ref _Value, newValue, oldValue) != oldValue); + _valueLong = _value.ToLong(); + TypeCode = TypeCode.Int64; + } - Visit(); + // 原子操作 + var newValue = Interlocked.Add(ref _valueLong, -value); + + VisitTime = Runtime.TickCount64; return newValue; } @@ -594,14 +623,14 @@ public Double Dec(Double value) { // 原子操作 Double newValue; - Object oldValue; + Object? oldValue; do { - oldValue = _Value ?? 0d; + oldValue = _value; newValue = (oldValue is Double n ? n : oldValue.ToDouble()) - value; - } while (Interlocked.CompareExchange(ref _Value, newValue, oldValue) != oldValue); + } while (Interlocked.CompareExchange(ref _value, newValue, oldValue) != oldValue); - Visit(); + VisitTime = Runtime.TickCount64; return newValue; } @@ -731,7 +760,8 @@ public void Save(Stream stream) bn.Write(item.Key); bn.Write((Int32)(ci.ExpiredTime / 1000)); - var type = ci.Value?.GetType(); + var value = ci.Value; + var type = value?.GetType(); if (type == null) { bn.Write((Byte)TypeCode.Empty); @@ -742,11 +772,11 @@ public void Save(Stream stream) bn.Write((Byte)code); if (code != TypeCode.Object) - bn.Write(ci.Value); + bn.Write(value); else { bn.Write(type.FullName); - if (ci.Value != null) bn.Write(Binary.FastWrite(ci.Value)); + if (value != null) bn.Write(Binary.FastWrite(value)); } } }