diff --git a/NewLife.Redis.Extensions/RedisCache.cs b/NewLife.Redis.Extensions/RedisCache.cs index 6d19a05..df80968 100644 --- a/NewLife.Redis.Extensions/RedisCache.cs +++ b/NewLife.Redis.Extensions/RedisCache.cs @@ -60,7 +60,7 @@ public void Set(String key, Byte[] value, DistributedCacheEntryOptions options) base.Set(key, value); else if (options.AbsoluteExpiration != null) - base.Set(key, value, options.AbsoluteExpiration.Value - DateTime.Now); + base.Set(key, value, options.AbsoluteExpiration.Value - DateTime.Now); else if (options.AbsoluteExpirationRelativeToNow != null) base.Set(key, value, options.AbsoluteExpirationRelativeToNow.Value); else if (options.SlidingExpiration != null) @@ -99,7 +99,7 @@ public void Set(String key, Byte[] value, DistributedCacheEntryOptions options) /// 删除 /// /// - public void Remove(String key) => base.Remove(key); + public new void Remove(String key) => base.Remove(key); /// /// 异步删除 diff --git a/NewLife.Redis/Clusters/RedisCluster.cs b/NewLife.Redis/Clusters/RedisCluster.cs index 1f1fe1e..bb9f0b5 100644 --- a/NewLife.Redis/Clusters/RedisCluster.cs +++ b/NewLife.Redis/Clusters/RedisCluster.cs @@ -12,7 +12,7 @@ public class RedisCluster : RedisBase, IRedisCluster, IDisposable IList IRedisCluster.Nodes => Nodes.Select(x => (IRedisNode)x).ToList(); /// 节点改变事件 - public event EventHandler NodeChanged; + public event EventHandler? NodeChanged; /// 集群节点 public ClusterNode[]? Nodes { get; private set; } diff --git a/NewLife.Redis/RedisClient.cs b/NewLife.Redis/RedisClient.cs index a04ca00..7339608 100644 --- a/NewLife.Redis/RedisClient.cs +++ b/NewLife.Redis/RedisClient.cs @@ -157,7 +157,7 @@ private Boolean OnCertificateValidationCallback(Object sender, X509Certificate c /// /// /// - protected virtual Int32 GetRequest(Memory memory, String cmd, Object[]? args) + protected virtual Int32 GetRequest(Memory memory, String cmd, Object?[]? args) { // *\r\n$\r\n\r\n // *1\r\n$4\r\nINFO\r\n @@ -200,12 +200,16 @@ protected virtual Int32 GetRequest(Memory memory, String cmd, Object[]? ar size = pk.Total; else { - pk = Host.Encoder.Encode(args[i]); - size = pk.Length; + var arg = args[i]; + if (arg != null) + { + pk = Host.Encoder.Encode(arg); + size = pk.Length; + } } // 指令日志。简单类型显示原始值,复杂类型显示序列化后字符串 - if (log != null && args != null) + if (log != null) { log.Append(' '); if (str != null) @@ -228,7 +232,7 @@ protected virtual Int32 GetRequest(Memory memory, String cmd, Object[]? ar writer.Write(str, -1); else if (buf != null) writer.Write(buf); - else + else if (pk != null) writer.Write(pk.GetSpan()); writer.Write(_NewLine); @@ -325,7 +329,7 @@ protected virtual Int32 GetRequest(Memory memory, String cmd, Object[]? ar /// 参数数组 /// 取消通知 /// - protected virtual async Task ExecuteCommandAsync(String cmd, Object[]? args, CancellationToken cancellationToken) + protected virtual async Task ExecuteCommandAsync(String cmd, Object?[]? args, CancellationToken cancellationToken) { var isQuit = cmd == "QUIT"; @@ -538,14 +542,16 @@ private static Int32 ReadLength(Stream ms) #endif } - private Int32 GetCommandSize(String cmd, Object[]? args) + private Int32 GetCommandSize(String cmd, Object?[]? args) { var total = 16 + cmd.Length; if (args != null) { foreach (var item in args) { - if (item is String str) + if (item == null) + total += 4; + else if (item is String str) total += 16 + Encoding.UTF8.GetByteCount(str); else if (item is Byte[] buf) total += 16 + buf.Length; @@ -595,7 +601,7 @@ private Int32 GetCommandSize(String cmd, Object[]? args) /// /// /// - public virtual Boolean TryExecute(String cmd, Object[] args, out TResult? value) + public virtual Boolean TryExecute(String cmd, Object?[] args, out TResult? value) { var rs = ExecuteAsync(cmd, args).Result; if (rs is TResult rs2) @@ -620,7 +626,7 @@ public virtual Boolean TryExecute(String cmd, Object[] args, out TResul /// 参数数组 /// 取消通知 /// - public virtual async Task ExecuteAsync(String cmd, Object[] args, CancellationToken cancellationToken = default) + public virtual async Task ExecuteAsync(String cmd, Object?[] args, CancellationToken cancellationToken = default) { // 埋点名称,支持二级命令 var act = cmd.EqualIgnoreCase("cluster", "xinfo", "xgroup", "xreadgroup") ? $"{cmd}-{args?.FirstOrDefault()}" : cmd; @@ -640,14 +646,14 @@ public virtual Boolean TryExecute(String cmd, Object[] args, out TResul /// 命令 /// 参数数组 /// - public virtual async Task ExecuteAsync(String cmd, params Object[] args) => await ExecuteAsync(cmd, args, CancellationToken.None); + public virtual async Task ExecuteAsync(String cmd, params Object?[] args) => await ExecuteAsync(cmd, args, CancellationToken.None); /// 异步执行命令。返回基本类型、对象、对象数组 /// 命令 /// 参数数组 /// 取消通知 /// - public virtual async Task ExecuteAsync(String cmd, Object[] args, CancellationToken cancellationToken) + public virtual async Task ExecuteAsync(String cmd, Object?[] args, CancellationToken cancellationToken) { // 管道模式 if (_ps != null) @@ -817,10 +823,10 @@ public virtual Boolean TryChangeType(Object value, Type type, out Object? target } } - private class Command(String name, Object[] args, Type type) + private class Command(String name, Object?[] args, Type type) { public String Name { get; } = name; - public Object[] Args { get; } = args; + public Object?[] Args { get; } = args; public Type Type { get; } = type; } #endregion diff --git a/NewLife.Redis/RedisEncoder.cs b/NewLife.Redis/RedisEncoder.cs index 57e2d6a..9754a5b 100644 --- a/NewLife.Redis/RedisEncoder.cs +++ b/NewLife.Redis/RedisEncoder.cs @@ -63,6 +63,10 @@ internal static IJsonHost GetJsonHost() return (ArrayPacket)str.GetBytes(); } + /// 解码数据包为目标类型 + /// + /// + /// public virtual Object? Decode(IPacket pk, Type type) { try @@ -101,9 +105,15 @@ internal static IJsonHost GetJsonHost() } } +/// 编解码助手 public static class RedisJsonEncoderHelper { //public static T Decode(this RedisJsonEncoder encoder, Packet pk) => (T)encoder.Decode(pk, typeof(T))!; + /// 解码数据包 + /// + /// + /// + /// public static T Decode(this IPacketEncoder encoder, IPacket pk) => (T)encoder.Decode(pk, typeof(T))!; } \ No newline at end of file diff --git a/NewLife.Redis/RedisHash.cs b/NewLife.Redis/RedisHash.cs index da69edc..58122a1 100644 --- a/NewLife.Redis/RedisHash.cs +++ b/NewLife.Redis/RedisHash.cs @@ -100,7 +100,7 @@ public IEnumerator> GetEnumerator() /// public Int32 HDel(params TKey[] fields) { - var args = new List + var args = new List { Key }; @@ -115,9 +115,9 @@ public Int32 HDel(params TKey[] fields) /// 只在 key 指定的哈希集中不存在指定的字段时,设置字段的值 /// /// - public TValue[] HMGet(params TKey[] fields) + public TValue[]? HMGet(params TKey[] fields) { - var args = new List + var args = new List { Key }; @@ -134,7 +134,7 @@ public TValue[] HMGet(params TKey[] fields) /// public Boolean HMSet(IEnumerable> keyValues) { - var args = new List + var args = new List { Key }; @@ -151,9 +151,10 @@ public Boolean HMSet(IEnumerable> keyValues) /// public IDictionary GetAll() { + var dic = new Dictionary(); var rs = Execute((r, k) => r.Execute("HGETALL", Key)); + if (rs == null || rs.Length == 0) return dic; - var dic = new Dictionary(); for (var i = 0; i < rs.Length; i++) { var pk = rs[i]; @@ -203,14 +204,15 @@ public virtual IEnumerable> Search(SearchModel model) model.Position = (rs[0] as IPacket)!.ToStr().ToInt(); - var ps = rs[1] as Object[]; + if (rs[1] is not Object[] ps) break; + for (var i = 0; i < ps.Length - 1; i += 2) { if (count-- > 0) { var key = (ps[i] as IPacket)!.ToStr().ChangeType(); var val = (ps[i + 1] as IPacket)!.ToStr().ChangeType(); - yield return new KeyValuePair(key, val); + if (key != null) yield return new KeyValuePair(key, val!); } } diff --git a/NewLife.Redis/RedisList.cs b/NewLife.Redis/RedisList.cs index 5bbc4f3..eeb22b1 100644 --- a/NewLife.Redis/RedisList.cs +++ b/NewLife.Redis/RedisList.cs @@ -128,7 +128,7 @@ public IEnumerator GetEnumerator() /// 队列元素总数 public Int32 RPUSH(IEnumerable values) { - var args = new List + var args = new List { Key }; @@ -144,7 +144,7 @@ public Int32 RPUSH(IEnumerable values) /// 队列元素总数 public Int32 LPUSH(IEnumerable values) { - var args = new List + var args = new List { Key }; @@ -157,11 +157,11 @@ public Int32 LPUSH(IEnumerable values) /// 移除并返回最右边一个元素 /// - public T RPOP() => Execute((rc, k) => rc.Execute("RPOP", Key), true); + public T? RPOP() => Execute((rc, k) => rc.Execute("RPOP", Key), true); /// 移除并返回最左边一个元素 /// - public T LPOP() => Execute((rc, k) => rc.Execute("LPOP", Key), true); + public T? LPOP() => Execute((rc, k) => rc.Execute("LPOP", Key), true); /// 移除并返回最右边一个元素,并插入目标列表左边,原子操作 /// @@ -169,7 +169,7 @@ public Int32 LPUSH(IEnumerable values) /// /// 目标列表 /// - public T RPOPLPUSH(String destKey) => Execute((rc, k) => rc.Execute("RPOPLPUSH", Key, GetKey(destKey)), true); + public T? RPOPLPUSH(String destKey) => Execute((rc, k) => rc.Execute("RPOPLPUSH", Key, GetKey(destKey)), true); /// 移除并返回最右边一个元素,并插入目标列表左边,原子操作 /// @@ -178,7 +178,7 @@ public Int32 LPUSH(IEnumerable values) /// 目标列表 /// 超时时间,默认0秒永远阻塞;负数表示直接返回,不阻塞。 /// - public T BRPOPLPUSH(String destKey, Int32 timeout) => Execute((rc, k) => rc.Execute("BRPOPLPUSH", Key, GetKey(destKey), timeout), true); + public T? BRPOPLPUSH(String destKey, Int32 timeout) => Execute((rc, k) => rc.Execute("BRPOPLPUSH", Key, GetKey(destKey), timeout), true); /// 在指定元素之前插入 ///