封装一个Redis服务组件

结构说明

 

ServiceCollectionExtensions类

 1 using com.project.Redis.Common;
 2 using Microsoft.Extensions.Configuration;
 3 using Microsoft.Extensions.DependencyInjection;
 4 using System;
 5 
 6 namespace com.project.Redis
 7 {
 8     public static class ServiceCollectionExtensions
 9     {
10         public static IServiceCollection AddRedis(this IServiceCollection services, IConfiguration configuration, string sectionName = "Redis")
11         {
12             if (services == null)
13             {
14                 throw new ArgumentNullException(nameof(services));
15             }
16             services.Configure<RedisOptions>(configuration.GetSection(sectionName));
17             services.AddSingleton<IRedisBuilder, RedisBuilder>();
18             return services;
19         }
20 
21         //public static IServiceCollection AddRedis(this IServiceCollection services, IConfiguration configuration)
22         //{
23         //    return new RedisBuilder(services, configuration);
24         //}
25     }
26 }

RedisOptions类

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Text;
 4 
 5 namespace com.project.Redis.Common
 6 {
 7     public class RedisOptions
 8     {
 9         public string Ip { get; set; }
10         public int Port { get; set; }
11         public string Password { get; set; }
12         public int DefaultDatabase { get; set; } = 1;
13 
14         /// <summary>
15         /// 需要连接的其他Database索引
16         /// </summary>
17         public string OtherDatabase { get; set; } = string.Empty;
18 
19         /// <summary>
20         /// The asynchronous method automatically uses pipeline, and the 10W concurrent time is 450ms (welcome to feedback) 默认值:false
21         /// </summary>
22         public bool AsyncPipeline { get; set; } = false;
23 
24         /// <summary>
25         /// 默认连接池数量是50个,也就是说一个微服务通过单例创建redisclient以后,通过CLIENT LIST可以查看到redisserver的连接数为50个。
26         /// 默认值:50
27         /// </summary>
28         public int Poolsize { get; set; } = 50;
29 
30         /// <summary>
31         /// Idle time of elements in the connection pool (MS), suitable for connecting to remote redis server
32         /// 默认值:2000
33         /// </summary>
34         public int IdleTimeout { get; set; } = 2000;
35 
36         /// <summary>
37         /// Connection timeout (MS)
38         /// 默认值:5000
39         /// </summary>
40         public int ConnectTimeout { get; set; } = 5000;
41 
42         /// <summary>
43         /// Send / receive timeout (MS)
44         /// 默认值:10000
45         /// </summary>
46         public int SyncTimeout { get; set; } = 10000;
47 
48         /// <summary>
49         /// Preheat connections, receive values such as preheat = 5 preheat 5 connections
50         /// 默认值:5
51         /// </summary>
52         public int Preheat { get; set; } = 5;
53 
54         /// <summary>
55         /// Follow system exit event to release automatically
56         /// 默认值:true
57         /// </summary>
58         public bool AutoDispose { get; set; } = true;
59 
60         /// <summary>
61         /// Enable encrypted transmission
62         /// 默认值:false
63         /// </summary>
64         public bool SSL { get; set; } = false;
65 
66         /// <summary>
67         /// 是否尝试集群模式,阿里云、腾讯云集群需要设置此选项为 false
68         /// true
69         /// </summary>
70         public bool Testcluster { get; set; } = true;
71 
72         /// <summary>
73         /// Execution error, retry attempts
74         /// 默认值:0
75         /// </summary>
76         public int Tryit { get; set; } = 0;
77 
78         /// <summary>
79         /// Connection name, use client list command to view
80         /// 客户端连接名称,在RedisServer上面使用Client list可以查看
81         /// 默认值:<Empty>
82         /// </summary>
83         public string Name { get; set; } = string.Empty;
84 
85         /// <summary>
86         /// key前辍,所有方法都会附带此前辍,csredis.Set(prefix + "key", 111);
87         /// 默认值:<Empty>
88         /// </summary>
89         public string Prefix { get; set; } = string.Empty;
90 
91         /// <summary>
92         /// 是否为redis集群,redis采用哨兵机制进行集群
93         /// 默认值:false
94         /// </summary>
95         public bool RedisCluster { get; set; } = false;
96     }
97 }

IRedisBuilder 接口类

 1 namespace com.project.Redis
 2 {
 3     public interface IRedisBuilder
 4     {
 5         /// <summary>
 6         /// 得到CSRedisClient操作对象
 7         /// </summary>
 8         /// <returns></returns>
 9         public CSRedis.CSRedisClient GetCSRedisClient();
10         /// <summary>
11         /// 得到CSRedisClient操作对象
12         /// </summary>
13         /// <param name="databaseIndex">database Index</param>
14         /// <returns></returns>
15         public CSRedis.CSRedisClient GetCSRedisClient(int databaseIndex);
16     }
17 }

RedisBuilder 类

 1 using com.project.Redis.Common;
 2 using CSRedis;
 3 using Microsoft.Extensions.Options;
 4 using System;
 5 using System.Collections.Generic;
 6 
 7 namespace com.project.Redis
 8 {
 9     /// <summary>
10     /// CSRedis客户端内部已经实现了连接池的管理,
11     /// 因此在全局单例CsRedisClient对象即可
12     /// </summary>
13     public class RedisBuilder : IRedisBuilder
14     {
15         private CSRedis.CSRedisClient _client;
16         /// <summary>
17         /// Redis操作客户端对象集合
18         /// </summary>
19         private Dictionary<int, CSRedis.CSRedisClient> _csredisclients;
20         /// <summary>
21         /// Redis连接参数
22         /// </summary>
23         private readonly RedisOptions _redisOptions;
24 
25         public RedisBuilder(IOptionsMonitor<RedisOptions> optionAccs)
26         {
27             _redisOptions = optionAccs.CurrentValue;
28             //127.0.0.1[:6379],password=123456,defaultDatabase=13,poolsize=50,ssl=false,writeBuffer=10240,prefix=key前辍
29             string connectionStringPrefix = string.Format("{0}:{1},password={2},poolsize={3},connectTimeout={4},ssl={5},writeBuffer=10240",
30                 _redisOptions.Ip,
31                 _redisOptions.Port,
32                 _redisOptions.Password,
33                 _redisOptions.Poolsize,
34                 _redisOptions.ConnectTimeout,
35                 _redisOptions.SSL);
36 
37             //测试 redis-cluster 不能设置 defaultDatabase
38             string defaultConnectionString = connectionStringPrefix;
39             if (!_redisOptions.RedisCluster)
40                 defaultConnectionString += $",defaultDatabase={_redisOptions.DefaultDatabase}";
41             if (!string.IsNullOrEmpty(_redisOptions.Prefix))
42                 defaultConnectionString += $",prefix={_redisOptions.Prefix}";
43             _client = new CSRedis.CSRedisClient(defaultConnectionString);
44 
45             if (!string.IsNullOrEmpty(_redisOptions.OtherDatabase))
46             {
47                 _csredisclients = new Dictionary<int, CSRedisClient>();
48                 if (_redisOptions.OtherDatabase.IndexOf(",") == -1)
49                 {
50                     string otherDatabaseConnectionString = connectionStringPrefix;
51                     otherDatabaseConnectionString += $",defaultDatabase={_redisOptions.OtherDatabase}";
52                     if (!string.IsNullOrEmpty(_redisOptions.Prefix))
53                         otherDatabaseConnectionString += $",prefix={_redisOptions.Prefix}";
54                     _csredisclients.Add(Convert.ToInt32(_redisOptions.OtherDatabase), new CSRedis.CSRedisClient(otherDatabaseConnectionString));
55                 }
56                 else
57                 {
58                     string[] otherDatabaseIndex = _redisOptions.OtherDatabase.Split(",");
59                     foreach (string index in otherDatabaseIndex)
60                     {
61                         string otherDatabaseConnectionString = connectionStringPrefix;
62                         otherDatabaseConnectionString += $",defaultDatabase={index}";
63                         if (!string.IsNullOrEmpty(_redisOptions.Prefix))
64                             otherDatabaseConnectionString += $",prefix={_redisOptions.Prefix}";
65                         _csredisclients.Add(Convert.ToInt32(index), new CSRedis.CSRedisClient(otherDatabaseConnectionString));
66                     }
67                 }
68             }
69         }
70 
71         /// <summary>
72         /// 得到CSRedisClient操作对象
73         /// </summary>
74         /// <returns></returns>
75         public CSRedisClient GetCSRedisClient()
76         {
77             return _client;
78         }
79 
80         /// <summary>
81         /// 得到CSRedisClient操作对象
82         /// </summary>
83         /// <param name="databaseIndex">database Index</param>
84         /// <returns></returns>
85         public CSRedisClient GetCSRedisClient(int databaseIndex)
86         {
87             return _csredisclients[databaseIndex];
88         }
89     }
90 }

CSRedisClient类

   1 using CSRedis.Internal.ObjectPool;
   2 using System;
   3 using System.Collections.Concurrent;
   4 using System.Collections.Generic;
   5 using System.Diagnostics;
   6 using System.Linq;
   7 using System.Text.RegularExpressions;
   8 using System.Threading;
   9 using System.Threading.Tasks;
  10 
  11 #if net40
  12 #else
  13 namespace CSRedis
  14 {
  15     public partial class CSRedisClient
  16     {
  17 
  18         ConcurrentDictionary<string, AutoPipe> _autoPipe = new ConcurrentDictionary<string, AutoPipe>();
  19         class AutoPipe
  20         {
  21             public Object<RedisClient> Client;
  22             public long GetTimes;
  23             public long TimesZore;
  24             public bool IsSingleEndPipe;
  25             public Exception ReturnException;
  26         }
  27         async Task<AutoPipe> GetClientAsync(RedisClientPool pool)
  28         {
  29             if (pool._policy._asyncPipeline == false)
  30                 return new AutoPipe { Client = await pool.GetAsync(), GetTimes = 1, TimesZore = 0, IsSingleEndPipe = false };
  31 
  32             if (_autoPipe.TryGetValue(pool.Key, out var ap) && ap.IsSingleEndPipe == false)
  33             {
  34                 if (pool.UnavailableException != null)
  35                     throw new Exception($"【{pool._policy.Name}】状态不可用,等待后台检查程序恢复方可使用。{pool.UnavailableException?.Message}", pool.UnavailableException);
  36                 Interlocked.Increment(ref ap.GetTimes);
  37                 return ap;
  38             }
  39             ap = new AutoPipe { Client = await pool.GetAsync(), GetTimes = 1, TimesZore = 0, IsSingleEndPipe = false };
  40             if (_autoPipe.TryAdd(pool.Key, ap))
  41             {
  42                 ap.Client.Value._asyncPipe = new ConcurrentQueue<TaskCompletionSource<object>>();
  43                 new Thread(() =>
  44                 {
  45                     var rc = ap.Client.Value;
  46 
  47                     void trySetException(Exception ex)
  48                     {
  49                         pool.SetUnavailable(ex);
  50                         while (rc._asyncPipe?.IsEmpty == false)
  51                         {
  52                             TaskCompletionSource<object> trytsc = null;
  53                             if (rc._asyncPipe?.TryDequeue(out trytsc) == true)
  54                                 trytsc.TrySetException(ex);
  55                         }
  56                         rc._asyncPipe = null;
  57                         pool.Return(ap.Client);
  58                         _autoPipe.TryRemove(pool.Key, out var oldap);
  59                     }
  60                     while (true)
  61                     {
  62                         Thread.CurrentThread.Join(1);
  63                         if (rc._asyncPipe?.IsEmpty == false)
  64                         {
  65                             try
  66                             {
  67                                 var ret = rc.EndPipe();
  68                                 if (ret.Length == 1) ap.IsSingleEndPipe = true;
  69                                 else if (ret.Length > 1) ap.IsSingleEndPipe = false;
  70                                 foreach (var rv in ret)
  71                                 {
  72                                     TaskCompletionSource<object> trytsc = null;
  73                                     if (rc._asyncPipe?.TryDequeue(out trytsc) == true)
  74                                         trytsc.TrySetResult(rv);
  75                                 }
  76                             }
  77                             catch (Exception ex)
  78                             {
  79                                 trySetException(ex);
  80                                 return;
  81                             }
  82                             continue;
  83                         }
  84 
  85                         if (ap.ReturnException != null)
  86                         {
  87                             trySetException(ap.ReturnException);
  88                             return;
  89                         }
  90                         var tmpTimes = Interlocked.Increment(ref ap.TimesZore);
  91                         if (tmpTimes >= 10) ap.IsSingleEndPipe = false;
  92                         if (tmpTimes >= 1000)
  93                         {
  94                             rc._asyncPipe = null;
  95                             pool.Return(ap.Client, ap.ReturnException);
  96                             _autoPipe.TryRemove(pool.Key, out var oldap);
  97                             break;
  98                         }
  99                     }
 100                 }).Start();
 101             }
 102             return ap;
 103         }
 104         void ReturnClient(AutoPipe ap, Object<RedisClient> obj, RedisClientPool pool, Exception ex)
 105         {
 106             if (ap == null) return;
 107             var times = Interlocked.Decrement(ref ap.GetTimes);
 108             if (times <= 0)
 109                 Interlocked.Exchange(ref ap.TimesZore, 0);
 110             ap.ReturnException = ex;
 111             if (_autoPipe.TryGetValue(pool.Key, out var dicap) == false || dicap != ap)
 112                 pool.Return(ap.Client, ap.ReturnException);
 113         }
 114 
 115         async Task<T> GetAndExecuteAsync<T>(RedisClientPool pool, Func<Object<RedisClient>, Task<T>> handerAsync, int jump = 100, int errtimes = 0)
 116         {
 117             AutoPipe ap = null;
 118             Object<RedisClient> obj = null;
 119             Exception ex = null;
 120             var redirect = ParseClusterRedirect(null);
 121             try
 122             {
 123                 ap = await GetClientAsync(pool);
 124                 obj = ap.Client;
 125                 while (true)
 126                 { //因网络出错重试,默认1次
 127                     try
 128                     {
 129                         var ret = await handerAsync(obj);
 130                         return ret;
 131                     }
 132                     catch (RedisException ex3)
 133                     {
 134                         redirect = ParseClusterRedirect(ex3); //官方集群跳转
 135                         if (redirect == null || jump <= 0)
 136                         {
 137                             ex = ex3;
 138                             if (SentinelManager != null && ex.Message.Contains("READONLY"))
 139                             { //哨兵轮询
 140                                 if (pool.SetUnavailable(ex) == true)
 141                                     BackgroundGetSentinelMasterValue();
 142                             }
 143                             throw ex;
 144                         }
 145                         break;
 146                     }
 147                     catch (Exception ex2)
 148                     {
 149                         ex = ex2;
 150                         if (pool.UnavailableException != null) throw ex;
 151                         var isPong = false;
 152                         try
 153                         {
 154                             await obj.Value.PingAsync();
 155                             isPong = true;
 156                         }
 157                         catch
 158                         {
 159                             obj.ResetValue();
 160                         }
 161 
 162                         if (isPong == false || ++errtimes > pool._policy._tryit)
 163                         {
 164                             if (SentinelManager != null)
 165                             { //哨兵轮询
 166                                 if (pool.SetUnavailable(ex) == true)
 167                                     BackgroundGetSentinelMasterValue();
 168                                 throw new Exception($"Redis Sentinel Master is switching:{ex.Message}");
 169                             }
 170                             throw ex; //重试次数完成
 171                         }
 172                         else
 173                         {
 174                             ex = null;
 175                             Trace.WriteLine($"csredis tryit ({errtimes}) ...");
 176                         }
 177                     }
 178                 }
 179             }
 180             finally
 181             {
 182                 ReturnClient(ap, obj, pool, ex);
 183                 //pool.Return(obj, ex);
 184             }
 185             if (redirect == null)
 186                 return await GetAndExecuteAsync<T>(pool, handerAsync, jump - 1, errtimes);
 187 
 188             var redirectHanderAsync = redirect.Value.isMoved ? handerAsync : async redirectObj =>
 189             {
 190                 await redirectObj.Value.CallAsync("ASKING");
 191                 return await handerAsync(redirectObj);
 192             };
 193             return await GetAndExecuteAsync<T>(GetRedirectPool(redirect.Value, pool), redirectHanderAsync, jump - 1);
 194         }
 195 
 196         async Task<T> NodesNotSupportAsync<T>(string[] keys, T defaultValue, Func<Object<RedisClient>, string[], Task<T>> callbackAsync)
 197         {
 198             if (keys == null || keys.Any() == false) return defaultValue;
 199             var rules = Nodes.Count > 1 ? keys.Select(a => NodeRuleRaw(a)).Distinct() : new[] { Nodes.FirstOrDefault().Key };
 200             if (rules.Count() > 1) throw new Exception("由于开启了分区模式,keys 分散在多个节点,无法使用此功能");
 201             var pool = Nodes.TryGetValue(rules.First(), out var b) ? b : Nodes.First().Value;
 202             string[] rkeys = new string[keys.Length];
 203             for (int a = 0; a < keys.Length; a++) rkeys[a] = string.Concat(pool.Prefix, keys[a]);
 204             if (rkeys.Length == 0) return defaultValue;
 205             return await GetAndExecuteAsync(pool, conn => callbackAsync(conn, rkeys));
 206         }
 207         Task<T> NodesNotSupportAsync<T>(string key, Func<Object<RedisClient>, string, Task<T>> callback)
 208         {
 209             if (IsMultiNode) throw new Exception("由于开启了分区模式,无法使用此功能");
 210             return ExecuteScalarAsync<T>(key, callback);
 211         }
 212 
 213 
 214         #region 缓存壳
 215         /// <summary>
 216         /// 缓存壳
 217         /// </summary>
 218         /// <typeparam name="T">缓存类型</typeparam>
 219         /// <param name="key">不含prefix前辍</param>
 220         /// <param name="timeoutSeconds">缓存秒数</param>
 221         /// <param name="getDataAsync">获取源数据的函数</param>
 222         /// <returns></returns>
 223         async public Task<T> CacheShellAsync<T>(string key, int timeoutSeconds, Func<Task<T>> getDataAsync)
 224         {
 225             if (timeoutSeconds == 0) return await getDataAsync();
 226             var cacheValue = await GetAsync(key);
 227             if (cacheValue != null)
 228             {
 229                 try
 230                 {
 231                     return this.DeserializeObject<T>(cacheValue);
 232                 }
 233                 catch
 234                 {
 235                     await DelAsync(key);
 236                     throw;
 237                 }
 238             }
 239             var ret = await getDataAsync();
 240             await SetAsync(key, this.SerializeObject(ret), timeoutSeconds);
 241             return ret;
 242         }
 243         /// <summary>
 244         /// 缓存壳(哈希表)
 245         /// </summary>
 246         /// <typeparam name="T">缓存类型</typeparam>
 247         /// <param name="key">不含prefix前辍</param>
 248         /// <param name="field">字段</param>
 249         /// <param name="timeoutSeconds">缓存秒数</param>
 250         /// <param name="getDataAsync">获取源数据的函数</param>
 251         /// <returns></returns>
 252         async public Task<T> CacheShellAsync<T>(string key, string field, int timeoutSeconds, Func<Task<T>> getDataAsync)
 253         {
 254             if (timeoutSeconds == 0) return await getDataAsync();
 255             var cacheValue = await HGetAsync(key, field);
 256             if (cacheValue != null)
 257             {
 258                 try
 259                 {
 260                     var value = this.DeserializeObject<(T, long)>(cacheValue);
 261                     if (DateTime.Now.Subtract(_dt1970.AddSeconds(value.Item2)).TotalSeconds <= timeoutSeconds) return value.Item1;
 262                 }
 263                 catch
 264                 {
 265                     await HDelAsync(key, field);
 266                     throw;
 267                 }
 268             }
 269             var ret = await getDataAsync();
 270             await HSetAsync(key, field, this.SerializeObject((ret, (long)DateTime.Now.Subtract(_dt1970).TotalSeconds)));
 271             return ret;
 272         }
 273         /// <summary>
 274         /// 缓存壳(哈希表),将 fields 每个元素存储到单独的缓存片,实现最大化复用
 275         /// </summary>
 276         /// <typeparam name="T">缓存类型</typeparam>
 277         /// <param name="key">不含prefix前辍</param>
 278         /// <param name="fields">字段</param>
 279         /// <param name="timeoutSeconds">缓存秒数</param>
 280         /// <param name="getDataAsync">获取源数据的函数,输入参数是没有缓存的 fields,返回值应该是 (field, value)[]</param>
 281         /// <returns></returns>
 282         async public Task<(string key, T value)[]> CacheShellAsync<T>(string key, string[] fields, int timeoutSeconds, Func<string[], Task<(string, T)[]>> getDataAsync)
 283         {
 284             fields = fields?.Distinct().ToArray();
 285             if (fields == null || fields.Length == 0) return new (string, T)[0];
 286             if (timeoutSeconds == 0) return await getDataAsync(fields);
 287 
 288             var ret = new (string, T)[fields.Length];
 289             var cacheValue = await HMGetAsync(key, fields);
 290             var fieldsMGet = new Dictionary<string, int>();
 291 
 292             for (var a = 0; a < ret.Length; a++)
 293             {
 294                 if (cacheValue[a] != null)
 295                 {
 296                     try
 297                     {
 298                         var value = this.DeserializeObject<(T, long)>(cacheValue[a]);
 299                         if (DateTime.Now.Subtract(_dt1970.AddSeconds(value.Item2)).TotalSeconds <= timeoutSeconds)
 300                         {
 301                             ret[a] = (fields[a], value.Item1);
 302                             continue;
 303                         }
 304                     }
 305                     catch
 306                     {
 307                         await HDelAsync(key, fields[a]);
 308                         throw;
 309                     }
 310                 }
 311                 fieldsMGet.Add(fields[a], a);
 312             }
 313 
 314             if (fieldsMGet.Any())
 315             {
 316                 var getDataIntput = fieldsMGet.Keys.ToArray();
 317                 var data = await getDataAsync(getDataIntput);
 318                 var mset = new object[fieldsMGet.Count * 2];
 319                 var msetIndex = 0;
 320                 foreach (var d in data)
 321                 {
 322                     if (fieldsMGet.ContainsKey(d.Item1) == false) throw new Exception($"使用 CacheShell 请确认 getData 返回值 (string, T)[] 中的 Item1 值: {d.Item1} 存在于 输入参数: {string.Join(",", getDataIntput)}");
 323                     ret[fieldsMGet[d.Item1]] = d;
 324                     mset[msetIndex++] = d.Item1;
 325                     mset[msetIndex++] = this.SerializeObject((d.Item2, (long)DateTime.Now.Subtract(_dt1970).TotalSeconds));
 326                     fieldsMGet.Remove(d.Item1);
 327                 }
 328                 foreach (var fieldNull in fieldsMGet.Keys)
 329                 {
 330                     ret[fieldsMGet[fieldNull]] = (fieldNull, default(T));
 331                     mset[msetIndex++] = fieldNull;
 332                     mset[msetIndex++] = this.SerializeObject((default(T), (long)DateTime.Now.Subtract(_dt1970).TotalSeconds));
 333                 }
 334                 if (mset.Any()) await HMSetAsync(key, mset);
 335             }
 336             return ret;
 337         }
 338         #endregion
 339 
 340         #region 分区方式 ExecuteAsync
 341         async private Task<T> ExecuteScalarAsync<T>(string key, Func<Object<RedisClient>, string, Task<T>> handerAsync)
 342         {
 343             if (key == null) return default(T);
 344             var pool = NodeRuleRaw == null || Nodes.Count == 1 ? Nodes.First().Value : (Nodes.TryGetValue(NodeRuleRaw(key), out var b) ? b : Nodes.First().Value);
 345             key = string.Concat(pool.Prefix, key);
 346             return await GetAndExecuteAsync(pool, conn => handerAsync(conn, key));
 347         }
 348         async private Task<T[]> ExecuteArrayAsync<T>(string[] key, Func<Object<RedisClient>, string[], Task<T[]>> handerAsync)
 349         {
 350             if (key == null || key.Any() == false) return new T[0];
 351             if (NodeRuleRaw == null || Nodes.Count == 1)
 352             {
 353                 var pool = Nodes.First().Value;
 354                 var keys = key.Select(a => string.Concat(pool.Prefix, a)).ToArray();
 355                 return await GetAndExecuteAsync(pool, conn => handerAsync(conn, keys));
 356             }
 357             var rules = new Dictionary<string, List<(string, int)>>();
 358             for (var a = 0; a < key.Length; a++)
 359             {
 360                 var rule = NodeRuleRaw(key[a]);
 361                 if (rules.ContainsKey(rule)) rules[rule].Add((key[a], a));
 362                 else rules.Add(rule, new List<(string, int)> { (key[a], a) });
 363             }
 364             T[] ret = new T[key.Length];
 365             foreach (var r in rules)
 366             {
 367                 var pool = Nodes.TryGetValue(r.Key, out var b) ? b : Nodes.First().Value;
 368                 var keys = r.Value.Select(a => string.Concat(pool.Prefix, a.Item1)).ToArray();
 369                 await GetAndExecuteAsync(pool, async conn =>
 370                 {
 371                     var vals = await handerAsync(conn, keys);
 372                     for (var z = 0; z < r.Value.Count; z++)
 373                     {
 374                         ret[r.Value[z].Item2] = vals == null || z >= vals.Length ? default(T) : vals[z];
 375                     }
 376                     return 0;
 377                 });
 378             }
 379             return ret;
 380         }
 381         async private Task<long> ExecuteNonQueryAsync(string[] key, Func<Object<RedisClient>, string[], Task<long>> handerAsync)
 382         {
 383             if (key == null || key.Any() == false) return 0;
 384             if (NodeRuleRaw == null || Nodes.Count == 1)
 385             {
 386                 var pool = Nodes.First().Value;
 387                 var keys = key.Select(a => string.Concat(pool.Prefix, a)).ToArray();
 388                 return await GetAndExecuteAsync(pool, conn => handerAsync(conn, keys));
 389             }
 390             var rules = new Dictionary<string, List<string>>();
 391             for (var a = 0; a < key.Length; a++)
 392             {
 393                 var rule = NodeRuleRaw(key[a]);
 394                 if (rules.ContainsKey(rule)) rules[rule].Add(key[a]);
 395                 else rules.Add(rule, new List<string> { key[a] });
 396             }
 397             long affrows = 0;
 398             foreach (var r in rules)
 399             {
 400                 var pool = Nodes.TryGetValue(r.Key, out var b) ? b : Nodes.First().Value;
 401                 var keys = r.Value.Select(a => string.Concat(pool.Prefix, a)).ToArray();
 402                 affrows += await GetAndExecuteAsync(pool, conn => handerAsync(conn, keys));
 403             }
 404             return affrows;
 405         }
 406         #endregion
 407 
 408         #region 服务器命令
 409         public partial class NodesServerManagerProvider
 410         {
 411 
 412             async Task<(string node, T value)[]> NodesInternalAsync<T>(Func<Object<RedisClient>, Task<T>> handleAsync)
 413             {
 414                 var ret = new List<(string, T)>();
 415                 foreach (var pool in _csredis.Nodes.Values)
 416                     ret.Add((pool.Key, await _csredis.GetAndExecuteAsync(pool, c => handleAsync(c))));
 417                 return ret.ToArray();
 418             }
 419 
 420             /// <summary>
 421             /// 异步执行一个 AOF(AppendOnly File) 文件重写操作
 422             /// </summary>
 423             /// <returns></returns>
 424             public Task<(string node, string value)[]> BgRewriteAofAsync() => NodesInternalAsync(c => c.Value.BgRewriteAofAsync());
 425             /// <summary>
 426             /// 在后台异步保存当前数据库的数据到磁盘
 427             /// </summary>
 428             /// <returns></returns>
 429             public Task<(string node, string value)[]> BgSaveAsync() => NodesInternalAsync(c => c.Value.BgSaveAsync());
 430             /// <summary>
 431             /// 关闭客户端连接
 432             /// </summary>
 433             /// <param name="ip">ip</param>
 434             /// <param name="port">端口</param>
 435             /// <returns></returns>
 436             public Task<(string node, string value)[]> ClientKillAsync(string ip, int port) => NodesInternalAsync(c => c.Value.ClientKillAsync(ip, port));
 437             /// <summary>
 438             /// 关闭客户端连接
 439             /// </summary>
 440             /// <param name="addr">ip:port</param>
 441             /// <param name="id">客户唯一标识</param>
 442             /// <param name="type">类型:normal | slave | pubsub</param>
 443             /// <param name="skipMe">跳过自己</param>
 444             /// <returns></returns>
 445             public Task<(string node, long value)[]> ClientKillAsync(string addr = null, string id = null, ClientKillType? type = null, bool? skipMe = null) => NodesInternalAsync(c => c.Value.ClientKillAsync(addr, id, type?.ToString(), skipMe));
 446             /// <summary>
 447             /// 获取连接到服务器的客户端连接列表
 448             /// </summary>
 449             /// <returns></returns>
 450             public Task<(string node, string value)[]> ClientListAsync() => NodesInternalAsync(c => c.Value.ClientListAsync());
 451             /// <summary>
 452             /// 获取连接的名称
 453             /// </summary>
 454             /// <returns></returns>
 455             public Task<(string node, string value)[]> ClientGetNameAsync() => NodesInternalAsync(c => c.Value.ClientGetNameAsync());
 456             /// <summary>
 457             /// 在指定时间内终止运行来自客户端的命令
 458             /// </summary>
 459             /// <param name="timeout">阻塞时间</param>
 460             /// <returns></returns>
 461             public Task<(string node, string value)[]> ClientPauseAsync(TimeSpan timeout) => NodesInternalAsync(c => c.Value.ClientPauseAsync(timeout));
 462             /// <summary>
 463             /// 设置当前连接的名称
 464             /// </summary>
 465             /// <param name="connectionName">连接名称</param>
 466             /// <returns></returns>
 467             public Task<(string node, string value)[]> ClientSetNameAsync(string connectionName) => NodesInternalAsync(c => c.Value.ClientSetNameAsync(connectionName));
 468             /// <summary>
 469             /// 返回当前服务器时间
 470             /// </summary>
 471             /// <returns></returns>
 472             public Task<(string node, DateTime value)[]> TimeAsync() => NodesInternalAsync(c => c.Value.TimeAsync());
 473             /// <summary>
 474             /// 获取指定配置参数的值
 475             /// </summary>
 476             /// <param name="parameter">参数</param>
 477             /// <returns></returns>
 478             public Task<(string node, Dictionary<string, string> value)[]> ConfigGetAsync(string parameter) => NodesInternalAsync(async c => (await c.Value.ConfigGetAsync(parameter)).ToDictionary(z => z.Item1, y => y.Item2));
 479             /// <summary>
 480             /// 对启动 Redis 服务器时所指定的 redis.conf 配置文件进行改写
 481             /// </summary>
 482             /// <returns></returns>
 483             public Task<(string node, string value)[]> ConfigRewriteAsync() => NodesInternalAsync(c => c.Value.ConfigRewriteAsync());
 484             /// <summary>
 485             /// 修改 redis 配置参数,无需重启
 486             /// </summary>
 487             /// <param name="parameter">参数</param>
 488             /// <param name="value"></param>
 489             /// <returns></returns>
 490             public Task<(string node, string value)[]> ConfigSetAsync(string parameter, string value) => NodesInternalAsync(c => c.Value.ConfigSetAsync(parameter, value));
 491             /// <summary>
 492             /// 重置 INFO 命令中的某些统计数据
 493             /// </summary>
 494             /// <returns></returns>
 495             public Task<(string node, string value)[]> ConfigResetStatAsync() => NodesInternalAsync(c => c.Value.ConfigResetStatAsync());
 496             /// <summary>
 497             /// 返回当前数据库的 key 的数量
 498             /// </summary>
 499             /// <returns></returns>
 500             public Task<(string node, long value)[]> DbSizeAsync() => NodesInternalAsync(c => c.Value.DbSizeAsync());
 501             /// <summary>
 502             /// 让 Redis 服务崩溃
 503             /// </summary>
 504             /// <returns></returns>
 505             public Task<(string node, string value)[]> DebugSegFaultAsync() => NodesInternalAsync(c => c.Value.DebugSegFaultAsync());
 506             /// <summary>
 507             /// 删除所有数据库的所有key
 508             /// </summary>
 509             /// <returns></returns>
 510             public Task<(string node, string value)[]> FlushAllAsync() => NodesInternalAsync(c => c.Value.FlushAllAsync());
 511             /// <summary>
 512             /// 删除当前数据库的所有key
 513             /// </summary>
 514             /// <returns></returns>
 515             public Task<(string node, string value)[]> FlushDbAsync() => NodesInternalAsync(c => c.Value.FlushDbAsync());
 516             /// <summary>
 517             /// 获取 Redis 服务器的各种信息和统计数值
 518             /// </summary>
 519             /// <param name="section">部分(all|default|server|clients|memory|persistence|stats|replication|cpu|commandstats|cluster|keyspace)</param>
 520             /// <returns></returns>
 521             public Task<(string node, string value)[]> InfoAsync(InfoSection? section = null) => NodesInternalAsync(c => c.Value.InfoAsync(section?.ToString()));
 522             /// <summary>
 523             /// 返回最近一次 Redis 成功将数据保存到磁盘上的时间
 524             /// </summary>
 525             /// <returns></returns>
 526             public Task<(string node, DateTime value)[]> LastSaveAsync() => NodesInternalAsync(c => c.Value.LastSaveAsync());
 527             /// <summary>
 528             /// 返回主从实例所属的角色
 529             /// </summary>
 530             /// <returns></returns>
 531             public Task<(string node, RedisRole value)[]> RoleAsync() => NodesInternalAsync(c => c.Value.RoleAsync());
 532             /// <summary>
 533             /// 同步保存数据到硬盘
 534             /// </summary>
 535             /// <returns></returns>
 536             public Task<(string node, string value)[]> SaveAsync() => NodesInternalAsync(c => c.Value.SaveAsync());
 537             /// <summary>
 538             /// 异步保存数据到硬盘,并关闭服务器
 539             /// </summary>
 540             /// <param name="isSave">是否保存</param>
 541             /// <returns></returns>
 542             public Task<(string node, string value)[]> ShutdownAsync(bool isSave = true) => NodesInternalAsync(c => c.Value.ShutdownAsync(isSave));
 543             /// <summary>
 544             /// 将服务器转变为指定服务器的从属服务器(slave server),如果当前服务器已经是某个主服务器(master server)的从属服务器,那么执行 SLAVEOF host port 将使当前服务器停止对旧主服务器的同步,丢弃旧数据集,转而开始对新主服务器进行同步。
 545             /// </summary>
 546             /// <param name="host">主机</param>
 547             /// <param name="port">端口</param>
 548             /// <returns></returns>
 549             public Task<(string node, string value)[]> SlaveOfAsync(string host, int port) => NodesInternalAsync(c => c.Value.SlaveOfAsync(host, port));
 550             /// <summary>
 551             /// 从属服务器执行命令 SLAVEOF NO ONE 将使得这个从属服务器关闭复制功能,并从从属服务器转变回主服务器,原来同步所得的数据集不会被丢弃。
 552             /// </summary>
 553             /// <returns></returns>
 554             public Task<(string node, string value)[]> SlaveOfNoOneAsync() => NodesInternalAsync(c => c.Value.SlaveOfNoOneAsync());
 555             /// <summary>
 556             /// 管理 redis 的慢日志,按数量获取
 557             /// </summary>
 558             /// <param name="count">数量</param>
 559             /// <returns></returns>
 560             public Task<(string node, RedisSlowLogEntry[] value)[]> SlowLogGetAsync(long? count = null) => NodesInternalAsync(c => c.Value.SlowLogGetAsync(count));
 561             /// <summary>
 562             /// 管理 redis 的慢日志,总数量
 563             /// </summary>
 564             /// <returns></returns>
 565             public Task<(string node, long value)[]> SlowLogLenAsync() => NodesInternalAsync(c => c.Value.SlowLogLenAsync());
 566             /// <summary>
 567             /// 管理 redis 的慢日志,清空
 568             /// </summary>
 569             /// <returns></returns>
 570             public Task<(string node, string value)[]> SlowLogResetAsync() => NodesInternalAsync(c => c.Value.SlowLogResetAsync());
 571             /// <summary>
 572             /// 用于复制功能(replication)的内部命令
 573             /// </summary>
 574             /// <returns></returns>
 575             public Task<(string node, byte[] value)[]> SyncAsync() => NodesInternalAsync(c => c.Value.SyncAsync());
 576         }
 577 
 578         public partial class NodeServerManagerProvider
 579         {
 580 
 581             /// <summary>
 582             /// 异步执行一个 AOF(AppendOnly File) 文件重写操作
 583             /// </summary>
 584             /// <returns></returns>
 585             public Task<string> BgRewriteAofAsync() => _csredis.GetAndExecute(_pool, c => c.Value.BgRewriteAofAsync());
 586             /// <summary>
 587             /// 在后台异步保存当前数据库的数据到磁盘
 588             /// </summary>
 589             /// <returns></returns>
 590             public Task<string> BgSaveAsync() => _csredis.GetAndExecute(_pool, c => c.Value.BgSaveAsync());
 591             /// <summary>
 592             /// 关闭客户端连接
 593             /// </summary>
 594             /// <param name="ip">ip</param>
 595             /// <param name="port">端口</param>
 596             /// <returns></returns>
 597             public Task<string> ClientKillAsync(string ip, int port) => _csredis.GetAndExecute(_pool, c => c.Value.ClientKillAsync(ip, port));
 598             /// <summary>
 599             /// 关闭客户端连接
 600             /// </summary>
 601             /// <param name="addr">ip:port</param>
 602             /// <param name="id">客户唯一标识</param>
 603             /// <param name="type">类型:normal | slave | pubsub</param>
 604             /// <param name="skipMe">跳过自己</param>
 605             /// <returns></returns>
 606             public Task<long> ClientKillAsync(string addr = null, string id = null, ClientKillType? type = null, bool? skipMe = null) => _csredis.GetAndExecute(_pool, c => c.Value.ClientKillAsync(addr, id, type?.ToString(), skipMe));
 607             /// <summary>
 608             /// 获取连接到服务器的客户端连接列表
 609             /// </summary>
 610             /// <returns></returns>
 611             public Task<string> ClientListAsync() => _csredis.GetAndExecute(_pool, c => c.Value.ClientListAsync());
 612             /// <summary>
 613             /// 获取连接的名称
 614             /// </summary>
 615             /// <returns></returns>
 616             public Task<string> ClientGetNameAsync() => _csredis.GetAndExecute(_pool, c => c.Value.ClientGetNameAsync());
 617             /// <summary>
 618             /// 在指定时间内终止运行来自客户端的命令
 619             /// </summary>
 620             /// <param name="timeout">阻塞时间</param>
 621             /// <returns></returns>
 622             public Task<string> ClientPauseAsync(TimeSpan timeout) => _csredis.GetAndExecute(_pool, c => c.Value.ClientPauseAsync(timeout));
 623             /// <summary>
 624             /// 设置当前连接的名称
 625             /// </summary>
 626             /// <param name="connectionName">连接名称</param>
 627             /// <returns></returns>
 628             public Task<string> ClientSetNameAsync(string connectionName) => _csredis.GetAndExecute(_pool, c => c.Value.ClientSetNameAsync(connectionName));
 629             /// <summary>
 630             /// 返回当前服务器时间
 631             /// </summary>
 632             /// <returns></returns>
 633             public Task<DateTime> TimeAsync() => _csredis.GetAndExecute(_pool, c => c.Value.TimeAsync());
 634             /// <summary>
 635             /// 获取指定配置参数的值
 636             /// </summary>
 637             /// <param name="parameter">参数</param>
 638             /// <returns></returns>
 639             async public Task<Dictionary<string, string>> ConfigGetAsync(string parameter) => (await _csredis.GetAndExecute(_pool, c => c.Value.ConfigGetAsync(parameter))).ToDictionary(z => z.Item1, y => y.Item2);
 640             /// <summary>
 641             /// 对启动 Redis 服务器时所指定的 redis.conf 配置文件进行改写
 642             /// </summary>
 643             /// <returns></returns>
 644             public Task<string> ConfigRewriteAsync() => _csredis.GetAndExecute(_pool, c => c.Value.ConfigRewriteAsync());
 645             /// <summary>
 646             /// 修改 redis 配置参数,无需重启
 647             /// </summary>
 648             /// <param name="parameter">参数</param>
 649             /// <param name="value"></param>
 650             /// <returns></returns>
 651             public Task<string> ConfigSetAsync(string parameter, string value) => _csredis.GetAndExecute(_pool, c => c.Value.ConfigSetAsync(parameter, value));
 652             /// <summary>
 653             /// 重置 INFO 命令中的某些统计数据
 654             /// </summary>
 655             /// <returns></returns>
 656             public Task<string> ConfigResetStatAsync() => _csredis.GetAndExecute(_pool, c => c.Value.ConfigResetStatAsync());
 657             /// <summary>
 658             /// 返回当前数据库的 key 的数量
 659             /// </summary>
 660             /// <returns></returns>
 661             public Task<long> DbSizeAsync() => _csredis.GetAndExecute(_pool, c => c.Value.DbSizeAsync());
 662             /// <summary>
 663             /// 让 Redis 服务崩溃
 664             /// </summary>
 665             /// <returns></returns>
 666             public Task<string> DebugSegFaultAsync() => _csredis.GetAndExecute(_pool, c => c.Value.DebugSegFaultAsync());
 667             /// <summary>
 668             /// 删除所有数据库的所有key
 669             /// </summary>
 670             /// <returns></returns>
 671             public Task<string> FlushAllAsync() => _csredis.GetAndExecute(_pool, c => c.Value.FlushAllAsync());
 672             /// <summary>
 673             /// 删除当前数据库的所有key
 674             /// </summary>
 675             /// <returns></returns>
 676             public Task<string> FlushDbAsync() => _csredis.GetAndExecute(_pool, c => c.Value.FlushDbAsync());
 677             /// <summary>
 678             /// 获取 Redis 服务器的各种信息和统计数值
 679             /// </summary>
 680             /// <param name="section">部分(Server | Clients | Memory | Persistence | Stats | Replication | CPU | Keyspace)</param>
 681             /// <returns></returns>
 682             public Task<string> InfoAsync(InfoSection? section = null) => _csredis.GetAndExecute(_pool, c => c.Value.InfoAsync(section?.ToString()));
 683             /// <summary>
 684             /// 返回最近一次 Redis 成功将数据保存到磁盘上的时间
 685             /// </summary>
 686             /// <returns></returns>
 687             public Task<DateTime> LastSaveAsync() => _csredis.GetAndExecute(_pool, c => c.Value.LastSaveAsync());
 688             /// <summary>
 689             /// 返回主从实例所属的角色
 690             /// </summary>
 691             /// <returns></returns>
 692             public Task<RedisRole> RoleAsync() => _csredis.GetAndExecute(_pool, c => c.Value.RoleAsync());
 693             /// <summary>
 694             /// 同步保存数据到硬盘
 695             /// </summary>
 696             /// <returns></returns>
 697             public Task<string> SaveAsync() => _csredis.GetAndExecute(_pool, c => c.Value.SaveAsync());
 698             /// <summary>
 699             /// 异步保存数据到硬盘,并关闭服务器
 700             /// </summary>
 701             /// <param name="isSave">是否保存</param>
 702             /// <returns></returns>
 703             public Task<string> ShutdownAsync(bool isSave = true) => _csredis.GetAndExecute(_pool, c => c.Value.ShutdownAsync(isSave));
 704             /// <summary>
 705             /// 将服务器转变为指定服务器的从属服务器(slave server),如果当前服务器已经是某个主服务器(master server)的从属服务器,那么执行 SLAVEOF host port 将使当前服务器停止对旧主服务器的同步,丢弃旧数据集,转而开始对新主服务器进行同步。
 706             /// </summary>
 707             /// <param name="host">主机</param>
 708             /// <param name="port">端口</param>
 709             /// <returns></returns>
 710             public Task<string> SlaveOfAsync(string host, int port) => _csredis.GetAndExecute(_pool, c => c.Value.SlaveOfAsync(host, port));
 711             /// <summary>
 712             /// 从属服务器执行命令 SLAVEOF NO ONE 将使得这个从属服务器关闭复制功能,并从从属服务器转变回主服务器,原来同步所得的数据集不会被丢弃。
 713             /// </summary>
 714             /// <returns></returns>
 715             public Task<string> SlaveOfNoOneAsync() => _csredis.GetAndExecute(_pool, c => c.Value.SlaveOfNoOneAsync());
 716             /// <summary>
 717             /// 管理 redis 的慢日志,按数量获取
 718             /// </summary>
 719             /// <param name="count">数量</param>
 720             /// <returns></returns>
 721             public Task<RedisSlowLogEntry[]> SlowLogGetAsync(long? count = null) => _csredis.GetAndExecute(_pool, c => c.Value.SlowLogGetAsync(count));
 722             /// <summary>
 723             /// 管理 redis 的慢日志,总数量
 724             /// </summary>
 725             /// <returns></returns>
 726             public Task<long> SlowLogLenAsync() => _csredis.GetAndExecute(_pool, c => c.Value.SlowLogLenAsync());
 727             /// <summary>
 728             /// 管理 redis 的慢日志,清空
 729             /// </summary>
 730             /// <returns></returns>
 731             public Task<string> SlowLogResetAsync() => _csredis.GetAndExecute(_pool, c => c.Value.SlowLogResetAsync());
 732             /// <summary>
 733             /// 用于复制功能(replication)的内部命令
 734             /// </summary>
 735             /// <returns></returns>
 736             public Task<byte[]> SyncAsync() => _csredis.GetAndExecute(_pool, c => c.Value.SyncAsync());
 737         }
 738         #endregion
 739 
 740         #region 连接命令
 741         /// <summary>
 742         /// 验证密码是否正确
 743         /// </summary>
 744         /// <param name="nodeKey">分区key</param>
 745         /// <param name="password">密码</param>
 746         /// <returns></returns>
 747         [Obsolete("不建议手工执行,连接池自己管理最佳")]
 748         private Task<bool> AuthAsync(string nodeKey, string password) => GetAndExecuteAsync(GetNodeOrThrowNotFound(nodeKey), async c => await c.Value.AuthAsync(password) == "OK");
 749         /// <summary>
 750         /// 打印字符串
 751         /// </summary>
 752         /// <param name="nodeKey">分区key</param>
 753         /// <param name="message">消息</param>
 754         /// <returns></returns>
 755         public Task<string> EchoAsync(string nodeKey, string message) => GetAndExecuteAsync(GetNodeOrThrowNotFound(nodeKey), c => c.Value.EchoAsync(message));
 756         /// <summary>
 757         /// 打印字符串
 758         /// </summary>
 759         /// <param name="message">消息</param>
 760         /// <returns></returns>
 761         public Task<string> EchoAsync(string message) => GetAndExecuteAsync(Nodes.First().Value, c => c.Value.EchoAsync(message));
 762         /// <summary>
 763         /// 查看服务是否运行
 764         /// </summary>
 765         /// <param name="nodeKey">分区key</param>
 766         /// <returns></returns>
 767         public Task<bool> PingAsync(string nodeKey) => GetAndExecuteAsync(GetNodeOrThrowNotFound(nodeKey), async c => await c.Value.PingAsync() == "PONG");
 768         /// <summary>
 769         /// 查看服务是否运行
 770         /// </summary>
 771         /// <returns></returns>
 772         public Task<bool> PingAsync() => GetAndExecuteAsync(Nodes.First().Value, async c => await c.Value.PingAsync() == "PONG");
 773         /// <summary>
 774         /// 关闭当前连接
 775         /// </summary>
 776         /// <param name="nodeKey">分区key</param>
 777         /// <returns></returns>
 778         [Obsolete("不建议手工执行,连接池自己管理最佳")]
 779         private Task<bool> QuitAsync(string nodeKey) => GetAndExecuteAsync(GetNodeOrThrowNotFound(nodeKey), async c => await c.Value.QuitAsync() == "OK");
 780         /// <summary>
 781         /// 切换到指定的数据库
 782         /// </summary>
 783         /// <param name="nodeKey">分区key</param>
 784         /// <param name="index">数据库</param>
 785         /// <returns></returns>
 786         [Obsolete("不建议手工执行,连接池所有连接应该指向同一数据库,若手工修改将导致数据的不一致")]
 787         private Task<bool> SelectAsync(string nodeKey, int index) => GetAndExecuteAsync(GetNodeOrThrowNotFound(nodeKey), async c => await c.Value.SelectAsync(index) == "OK");
 788         #endregion
 789 
 790         #region Script
 791         /// <summary>
 792         /// 执行脚本
 793         /// </summary>
 794         /// <param name="script">Lua 脚本</param>
 795         /// <param name="key">用于定位分区节点,不含prefix前辍</param>
 796         /// <param name="args">参数</param>
 797         /// <returns></returns>
 798         public Task<object> EvalAsync(string script, string key, params object[] args)
 799         {
 800             var args2 = args?.Select(z => this.SerializeRedisValueInternal(z)).ToArray();
 801             return ExecuteScalarAsync(key, (c, k) => c.Value.EvalAsync(script, new[] { k }, args2));
 802         }
 803         /// <summary>
 804         /// 执行脚本
 805         /// </summary>
 806         /// <param name="sha1">脚本缓存的sha1</param>
 807         /// <param name="key">用于定位分区节点,不含prefix前辍</param>
 808         /// <param name="args">参数</param>
 809         /// <returns></returns>
 810         public Task<object> EvalSHAAsync(string sha1, string key, params object[] args)
 811         {
 812             var args2 = args?.Select(z => this.SerializeRedisValueInternal(z)).ToArray();
 813             return ExecuteScalarAsync(key, (c, k) => c.Value.EvalSHAAsync(sha1, new[] { k }, args2));
 814         }
 815         /// <summary>
 816         /// 校验所有分区节点中,脚本是否已经缓存。任何分区节点未缓存sha1,都返回false。
 817         /// </summary>
 818         /// <param name="sha1">脚本缓存的sha1</param>
 819         /// <returns></returns>
 820         async public Task<bool[]> ScriptExistsAsync(params string[] sha1)
 821         {
 822             var ret = new List<bool>();
 823             foreach (var pool in Nodes.Values)
 824                 ret.Add((await GetAndExecuteAsync(pool, c => c.Value.ScriptExistsAsync(sha1)))?.Where(z => z == false).Any() == false);
 825             return ret.ToArray();
 826         }
 827         /// <summary>
 828         /// 清除所有分区节点中,所有 Lua 脚本缓存
 829         /// </summary>
 830         async public Task ScriptFlushAsync()
 831         {
 832             foreach (var pool in Nodes.Values)
 833                 await GetAndExecuteAsync(pool, c => c.Value.ScriptFlushAsync());
 834         }
 835         /// <summary>
 836         /// 杀死所有分区节点中,当前正在运行的 Lua 脚本
 837         /// </summary>
 838         async public Task ScriptKillAsync()
 839         {
 840             foreach (var pool in Nodes.Values)
 841                 await GetAndExecuteAsync(pool, c => c.Value.ScriptKillAsync());
 842         }
 843         /// <summary>
 844         /// 在所有分区节点中,缓存脚本后返回 sha1(同样的脚本在任何服务器,缓存后的 sha1 都是相同的)
 845         /// </summary>
 846         /// <param name="script">Lua 脚本</param>
 847         /// <returns></returns>
 848         async public Task<string> ScriptLoadAsync(string script)
 849         {
 850             string sha1 = null;
 851             foreach (var pool in Nodes.Values)
 852                 sha1 = await GetAndExecuteAsync(pool, c => c.Value.ScriptLoadAsync(script));
 853             return sha1;
 854         }
 855         #endregion
 856 
 857         #region Pub/Sub
 858         /// <summary>
 859         /// 用于将信息发送到指定分区节点的频道,最终消息发布格式:1|message
 860         /// </summary>
 861         /// <param name="channel">频道名</param>
 862         /// <param name="message">消息文本</param>
 863         /// <returns></returns>
 864         async public Task<long> PublishAsync(string channel, string message)
 865         {
 866             var msgid = await HIncrByAsync("csredisclient:Publish:msgid", channel, 1);
 867             return await ExecuteScalarAsync(channel, (c, k) => c.Value.PublishAsync(channel, $"{msgid}|{message}"));
 868         }
 869         /// <summary>
 870         /// 用于将信息发送到指定分区节点的频道,与 Publish 方法不同,不返回消息id头,即 1|
 871         /// </summary>
 872         /// <param name="channel">频道名</param>
 873         /// <param name="message">消息文本</param>
 874         /// <returns></returns>
 875         public Task<long> PublishNoneMessageIdAsync(string channel, string message) => ExecuteScalarAsync(channel, (c, k) => c.Value.PublishAsync(channel, message));
 876         /// <summary>
 877         /// 查看所有订阅频道
 878         /// </summary>
 879         /// <param name="pattern"></param>
 880         /// <returns></returns>
 881         async public Task<string[]> PubSubChannelsAsync(string pattern)
 882         {
 883             var ret = new List<string>();
 884             foreach (var pool in Nodes.Values)
 885                 ret.AddRange(await GetAndExecuteAsync(pool, c => c.Value.PubSubChannelsAsync(pattern)));
 886             return ret.ToArray();
 887         }
 888         /// <summary>
 889         /// 查看所有模糊订阅端的数量
 890         /// </summary>
 891         /// <returns></returns>
 892         [Obsolete("分区模式下,其他客户端的模糊订阅可能不会返回")]
 893         public Task<long> PubSubNumPatAsync() => GetAndExecuteAsync(Nodes.First().Value, c => c.Value.PubSubNumPatAsync());
 894         /// <summary>
 895         /// 查看所有订阅端的数量
 896         /// </summary>
 897         /// <param name="channels">频道</param>
 898         /// <returns></returns>
 899         [Obsolete("分区模式下,其他客户端的订阅可能不会返回")]
 900         async public Task<Dictionary<string, long>> PubSubNumSubAsync(params string[] channels) => (await ExecuteArrayAsync(channels, (c, k) =>
 901         {
 902             var prefix = (c.Pool as RedisClientPool).Prefix;
 903             return c.Value.PubSubNumSubAsync(k.Select(z => string.IsNullOrEmpty(prefix) == false && z.StartsWith(prefix) ? z.Substring(prefix.Length) : z).ToArray());
 904         })).ToDictionary(z => z.Item1, y => y.Item2);
 905         #endregion
 906 
 907         #region HyperLogLog
 908         /// <summary>
 909         /// 添加指定元素到 HyperLogLog
 910         /// </summary>
 911         /// <param name="key">不含prefix前辍</param>
 912         /// <param name="elements">元素</param>
 913         /// <returns></returns>
 914         async public Task<bool> PfAddAsync<T>(string key, params T[] elements)
 915         {
 916             if (elements == null || elements.Any() == false) return false;
 917             var args = elements.Select(z => this.SerializeRedisValueInternal(z)).ToArray();
 918             return await ExecuteScalarAsync(key, (c, k) => c.Value.PfAddAsync(k, args));
 919         }
 920         /// <summary>
 921         /// 返回给定 HyperLogLog 的基数估算值
 922         /// </summary>
 923         /// <param name="keys">不含prefix前辍</param>
 924         /// <returns></returns>
 925         [Obsolete("分区模式下,若keys分散在多个分区节点时,将报错")]
 926         public Task<long> PfCountAsync(params string[] keys) => NodesNotSupportAsync(keys, 0, (c, k) => c.Value.PfCountAsync(k));
 927         /// <summary>
 928         /// 将多个 HyperLogLog 合并为一个 HyperLogLog
 929         /// </summary>
 930         /// <param name="destKey">新的 HyperLogLog,不含prefix前辍</param>
 931         /// <param name="sourceKeys">源 HyperLogLog,不含prefix前辍</param>
 932         /// <returns></returns>
 933         [Obsolete("分区模式下,若keys分散在多个分区节点时,将报错")]
 934         public Task<bool> PfMergeAsync(string destKey, params string[] sourceKeys) => NodesNotSupportAsync(new[] { destKey }.Concat(sourceKeys).ToArray(), false, async (c, k) => await c.Value.PfMergeAsync(k.First(), k.Skip(1).ToArray()) == "OK");
 935         #endregion
 936 
 937         #region Sorted Set
 938         /// <summary>
 939         /// [redis-server 5.0.0] 删除并返回有序集合key中的最多count个具有最高得分的成员。如未指定,count的默认值为1。指定一个大于有序集合的基数的count不会产生错误。 当返回多个元素时候,得分最高的元素将是第一个元素,然后是分数较低的元素。
 940         /// </summary>
 941         /// <param name="key">不含prefix前辍</param>
 942         /// <param name="count">数量</param>
 943         /// <returns></returns>
 944         async public Task<(string member, decimal score)[]> ZPopMaxAsync(string key, long count) => (await ExecuteScalarAsync(key, (c, k) => c.Value.ZPopMaxAsync(k, count))).Select(a => (a.Item1, a.Item2)).ToArray();
 945         /// <summary>
 946         /// [redis-server 5.0.0] 删除并返回有序集合key中的最多count个具有最高得分的成员。如未指定,count的默认值为1。指定一个大于有序集合的基数的count不会产生错误。 当返回多个元素时候,得分最高的元素将是第一个元素,然后是分数较低的元素。
 947         /// </summary>
 948         /// <param name="key">不含prefix前辍</param>
 949         /// <param name="count">数量</param>
 950         /// <returns></returns>
 951         async public Task<(T member, decimal score)[]> ZPopMaxAsync<T>(string key, long count) => this.DeserializeRedisValueTuple1Internal<T, decimal>(await ExecuteScalarAsync(key, (c, k) => c.Value.ZPopMaxBytesAsync(k, count)));
 952         /// <summary>
 953         /// [redis-server 5.0.0] 删除并返回有序集合key中的最多count个具有最低得分的成员。如未指定,count的默认值为1。指定一个大于有序集合的基数的count不会产生错误。 当返回多个元素时候,得分最低的元素将是第一个元素,然后是分数较高的元素。
 954         /// </summary>
 955         /// <param name="key">不含prefix前辍</param>
 956         /// <param name="count">数量</param>
 957         /// <returns></returns>
 958         async public Task<(string member, decimal score)[]> ZPopMinAsync(string key, long count) => (await ExecuteScalarAsync(key, (c, k) => c.Value.ZPopMinAsync(k, count))).Select(a => (a.Item1, a.Item2)).ToArray();
 959         /// <summary>
 960         /// [redis-server 5.0.0] 删除并返回有序集合key中的最多count个具有最低得分的成员。如未指定,count的默认值为1。指定一个大于有序集合的基数的count不会产生错误。 当返回多个元素时候,得分最低的元素将是第一个元素,然后是分数较高的元素。
 961         /// </summary>
 962         /// <param name="key">不含prefix前辍</param>
 963         /// <param name="count">数量</param>
 964         /// <returns></returns>
 965         async public Task<(T member, decimal score)[]> ZPopMinAsync<T>(string key, long count) => this.DeserializeRedisValueTuple1Internal<T, decimal>(await ExecuteScalarAsync(key, (c, k) => c.Value.ZPopMinBytesAsync(k, count)));
 966 
 967         /// <summary>
 968         /// 向有序集合添加一个或多个成员,或者更新已存在成员的分数
 969         /// </summary>
 970         /// <param name="key">不含prefix前辍</param>
 971         /// <param name="scoreMembers">一个或多个成员分数</param>
 972         /// <returns></returns>
 973         async public Task<long> ZAddAsync(string key, params (decimal, object)[] scoreMembers)
 974         {
 975             if (scoreMembers == null || scoreMembers.Any() == false) return 0;
 976             var args = scoreMembers.Select(a => new Tuple<decimal, object>(a.Item1, this.SerializeRedisValueInternal(a.Item2))).ToArray();
 977             return await ExecuteScalarAsync(key, (c, k) => c.Value.ZAddAsync(k, args));
 978         }
 979         /// <summary>
 980         /// 获取有序集合的成员数量
 981         /// </summary>
 982         /// <param name="key">不含prefix前辍</param>
 983         /// <returns></returns>
 984         public Task<long> ZCardAsync(string key) => ExecuteScalarAsync(key, (c, k) => c.Value.ZCardAsync(k));
 985         /// <summary>
 986         /// 计算在有序集合中指定区间分数的成员数量
 987         /// </summary>
 988         /// <param name="key">不含prefix前辍</param>
 989         /// <param name="min">分数最小值 decimal.MinValue 1</param>
 990         /// <param name="max">分数最大值 decimal.MaxValue 10</param>
 991         /// <returns></returns>
 992         public Task<long> ZCountAsync(string key, decimal min, decimal max) => ExecuteScalarAsync(key, (c, k) => c.Value.ZCountAsync(k, min == decimal.MinValue ? "-inf" : min.ToString(), max == decimal.MaxValue ? "+inf" : max.ToString()));
 993         /// <summary>
 994         /// 计算在有序集合中指定区间分数的成员数量
 995         /// </summary>
 996         /// <param name="key">不含prefix前辍</param>
 997         /// <param name="min">分数最小值 -inf (1 1</param>
 998         /// <param name="max">分数最大值 +inf (10 10</param>
 999         /// <returns></returns>
1000         public Task<long> ZCountAsync(string key, string min, string max) => ExecuteScalarAsync(key, (c, k) => c.Value.ZCountAsync(k, min, max));
1001         /// <summary>
1002         /// 有序集合中对指定成员的分数加上增量 increment
1003         /// </summary>
1004         /// <param name="key">不含prefix前辍</param>
1005         /// <param name="member">成员</param>
1006         /// <param name="increment">增量值(默认=1)</param>
1007         /// <returns></returns>
1008         public Task<decimal> ZIncrByAsync(string key, string member, decimal increment = 1)
1009         {
1010             var args = this.SerializeRedisValueInternal(member);
1011             return ExecuteScalarAsync(key, (c, k) => c.Value.ZIncrByAsync(k, increment, args));
1012         }
1013 
1014         /// <summary>
1015         /// 计算给定的一个或多个有序集的交集,将结果集存储在新的有序集合 destination 中
1016         /// </summary>
1017         /// <param name="destination">新的有序集合,不含prefix前辍</param>
1018         /// <param name="weights">使用 WEIGHTS 选项,你可以为 每个 给定有序集 分别 指定一个乘法因子。如果没有指定 WEIGHTS 选项,乘法因子默认设置为 1 。</param>
1019         /// <param name="aggregate">Sum | Min | Max</param>
1020         /// <param name="keys">一个或多个有序集合,不含prefix前辍</param>
1021         /// <returns></returns>
1022         public Task<long> ZInterStoreAsync(string destination, decimal[] weights, RedisAggregate aggregate, params string[] keys)
1023         {
1024             if (keys == null || keys.Length == 0) throw new Exception("keys 参数不可为空");
1025             if (weights != null && weights.Length != keys.Length) throw new Exception("weights 和 keys 参数长度必须相同");
1026             return NodesNotSupportAsync(new[] { destination }.Concat(keys).ToArray(), 0, (c, k) => c.Value.ZInterStoreAsync(k.First(), weights, aggregate, k.Skip(1).ToArray()));
1027         }
1028 
1029         /// <summary>
1030         /// 通过索引区间返回有序集合成指定区间内的成员
1031         /// </summary>
1032         /// <param name="key">不含prefix前辍</param>
1033         /// <param name="start">开始位置,0表示第一个元素,-1表示最后一个元素</param>
1034         /// <param name="stop">结束位置,0表示第一个元素,-1表示最后一个元素</param>
1035         /// <returns></returns>
1036         public Task<string[]> ZRangeAsync(string key, long start, long stop) => ExecuteScalarAsync(key, (c, k) => c.Value.ZRangeAsync(k, start, stop, false));
1037         /// <summary>
1038         /// 通过索引区间返回有序集合成指定区间内的成员
1039         /// </summary>
1040         /// <typeparam name="T">byte[] 或其他类型</typeparam>
1041         /// <param name="key">不含prefix前辍</param>
1042         /// <param name="start">开始位置,0表示第一个元素,-1表示最后一个元素</param>
1043         /// <param name="stop">结束位置,0表示第一个元素,-1表示最后一个元素</param>
1044         /// <returns></returns>
1045         async public Task<T[]> ZRangeAsync<T>(string key, long start, long stop) => this.DeserializeRedisValueArrayInternal<T>(await ExecuteScalarAsync(key, (c, k) => c.Value.ZRangeBytesAsync(k, start, stop, false)));
1046         /// <summary>
1047         /// 通过索引区间返回有序集合成指定区间内的成员和分数
1048         /// </summary>
1049         /// <param name="key">不含prefix前辍</param>
1050         /// <param name="start">开始位置,0表示第一个元素,-1表示最后一个元素</param>
1051         /// <param name="stop">结束位置,0表示第一个元素,-1表示最后一个元素</param>
1052         /// <returns></returns>
1053         async public Task<(string member, decimal score)[]> ZRangeWithScoresAsync(string key, long start, long stop) => (await ExecuteScalarAsync(key, (c, k) => c.Value.ZRangeWithScoresAsync(k, start, stop))).Select(a => (a.Item1, a.Item2)).ToArray();
1054         /// <summary>
1055         /// 通过索引区间返回有序集合成指定区间内的成员和分数
1056         /// </summary>
1057         /// <typeparam name="T">byte[] 或其他类型</typeparam>
1058         /// <param name="key">不含prefix前辍</param>
1059         /// <param name="start">开始位置,0表示第一个元素,-1表示最后一个元素</param>
1060         /// <param name="stop">结束位置,0表示第一个元素,-1表示最后一个元素</param>
1061         /// <returns></returns>
1062         async public Task<(T member, decimal score)[]> ZRangeWithScoresAsync<T>(string key, long start, long stop) => this.DeserializeRedisValueTuple1Internal<T, decimal>(await ExecuteScalarAsync(key, (c, k) => c.Value.ZRangeBytesWithScoresAsync(k, start, stop)));
1063 
1064         /// <summary>
1065         /// 通过分数返回有序集合指定区间内的成员
1066         /// </summary>
1067         /// <param name="key">不含prefix前辍</param>
1068         /// <param name="min">分数最小值 decimal.MinValue 1</param>
1069         /// <param name="max">分数最大值 decimal.MaxValue 10</param>
1070         /// <param name="count">返回多少成员</param>
1071         /// <param name="offset">返回条件偏移位置</param>
1072         /// <returns></returns>
1073         public Task<string[]> ZRangeByScoreAsync(string key, decimal min, decimal max, long? count = null, long offset = 0) =>
1074             ExecuteScalarAsync(key, (c, k) => c.Value.ZRangeByScoreAsync(k, min == decimal.MinValue ? "-inf" : min.ToString(), max == decimal.MaxValue ? "+inf" : max.ToString(), false, offset, count));
1075         /// <summary>
1076         /// 通过分数返回有序集合指定区间内的成员
1077         /// </summary>
1078         /// <typeparam name="T">byte[] 或其他类型</typeparam>
1079         /// <param name="key">不含prefix前辍</param>
1080         /// <param name="min">分数最小值 decimal.MinValue 1</param>
1081         /// <param name="max">分数最大值 decimal.MaxValue 10</param>
1082         /// <param name="count">返回多少成员</param>
1083         /// <param name="offset">返回条件偏移位置</param>
1084         /// <returns></returns>
1085         async public Task<T[]> ZRangeByScoreAsync<T>(string key, decimal min, decimal max, long? count = null, long offset = 0) =>
1086             this.DeserializeRedisValueArrayInternal<T>(await ExecuteScalarAsync(key, (c, k) => c.Value.ZRangeBytesByScoreAsync(k, min == decimal.MinValue ? "-inf" : min.ToString(), max == decimal.MaxValue ? "+inf" : max.ToString(), false, offset, count)));
1087         /// <summary>
1088         /// 通过分数返回有序集合指定区间内的成员
1089         /// </summary>
1090         /// <param name="key">不含prefix前辍</param>
1091         /// <param name="min">分数最小值 -inf (1 1</param>
1092         /// <param name="max">分数最大值 +inf (10 10</param>
1093         /// <param name="count">返回多少成员</param>
1094         /// <param name="offset">返回条件偏移位置</param>
1095         /// <returns></returns>
1096         public Task<string[]> ZRangeByScoreAsync(string key, string min, string max, long? count = null, long offset = 0) =>
1097             ExecuteScalarAsync(key, (c, k) => c.Value.ZRangeByScoreAsync(k, min, max, false, offset, count));
1098         /// <summary>
1099         /// 通过分数返回有序集合指定区间内的成员
1100         /// </summary>
1101         /// <typeparam name="T">byte[] 或其他类型</typeparam>
1102         /// <param name="key">不含prefix前辍</param>
1103         /// <param name="min">分数最小值 -inf (1 1</param>
1104         /// <param name="max">分数最大值 +inf (10 10</param>
1105         /// <param name="count">返回多少成员</param>
1106         /// <param name="offset">返回条件偏移位置</param>
1107         /// <returns></returns>
1108         async public Task<T[]> ZRangeByScoreAsync<T>(string key, string min, string max, long? count = null, long offset = 0) =>
1109             this.DeserializeRedisValueArrayInternal<T>(await ExecuteScalarAsync(key, (c, k) => c.Value.ZRangeBytesByScoreAsync(k, min, max, false, offset, count)));
1110 
1111         /// <summary>
1112         /// 通过分数返回有序集合指定区间内的成员和分数
1113         /// </summary>
1114         /// <param name="key">不含prefix前辍</param>
1115         /// <param name="min">分数最小值 decimal.MinValue 1</param>
1116         /// <param name="max">分数最大值 decimal.MaxValue 10</param>
1117         /// <param name="count">返回多少成员</param>
1118         /// <param name="offset">返回条件偏移位置</param>
1119         /// <returns></returns>
1120         async public Task<(string member, decimal score)[]> ZRangeByScoreWithScoresAsync(string key, decimal min, decimal max, long? count = null, long offset = 0) =>
1121             (await ExecuteScalarAsync(key, (c, k) => c.Value.ZRangeByScoreWithScoresAsync(k, min == decimal.MinValue ? "-inf" : min.ToString(), max == decimal.MaxValue ? "+inf" : max.ToString(), offset, count))).Select(z => (z.Item1, z.Item2)).ToArray();
1122         /// <summary>
1123         /// 通过分数返回有序集合指定区间内的成员和分数
1124         /// </summary>
1125         /// <typeparam name="T">byte[] 或其他类型</typeparam>
1126         /// <param name="key">不含prefix前辍</param>
1127         /// <param name="min">分数最小值 decimal.MinValue 1</param>
1128         /// <param name="max">分数最大值 decimal.MaxValue 10</param>
1129         /// <param name="count">返回多少成员</param>
1130         /// <param name="offset">返回条件偏移位置</param>
1131         /// <returns></returns>
1132         async public Task<(T member, decimal score)[]> ZRangeByScoreWithScoresAsync<T>(string key, decimal min, decimal max, long? count = null, long offset = 0) =>
1133             this.DeserializeRedisValueTuple1Internal<T, decimal>(await ExecuteScalarAsync(key, (c, k) => c.Value.ZRangeBytesByScoreWithScoresAsync(k, min == decimal.MinValue ? "-inf" : min.ToString(), max == decimal.MaxValue ? "+inf" : max.ToString(), offset, count)));
1134         /// <summary>
1135         /// 通过分数返回有序集合指定区间内的成员和分数
1136         /// </summary>
1137         /// <param name="key">不含prefix前辍</param>
1138         /// <param name="min">分数最小值 -inf (1 1</param>
1139         /// <param name="max">分数最大值 +inf (10 10</param>
1140         /// <param name="count">返回多少成员</param>
1141         /// <param name="offset">返回条件偏移位置</param>
1142         /// <returns></returns>
1143         async public Task<(string member, decimal score)[]> ZRangeByScoreWithScoresAsync(string key, string min, string max, long? count = null, long offset = 0) =>
1144             (await ExecuteScalarAsync(key, (c, k) => c.Value.ZRangeByScoreWithScoresAsync(k, min, max, offset, count))).Select(z => (z.Item1, z.Item2)).ToArray();
1145         /// <summary>
1146         /// 通过分数返回有序集合指定区间内的成员和分数
1147         /// </summary>
1148         /// <typeparam name="T">byte[] 或其他类型</typeparam>
1149         /// <param name="key">不含prefix前辍</param>
1150         /// <param name="min">分数最小值 -inf (1 1</param>
1151         /// <param name="max">分数最大值 +inf (10 10</param>
1152         /// <param name="count">返回多少成员</param>
1153         /// <param name="offset">返回条件偏移位置</param>
1154         /// <returns></returns>
1155         async public Task<(T member, decimal score)[]> ZRangeByScoreWithScoresAsync<T>(string key, string min, string max, long? count = null, long offset = 0) =>
1156             this.DeserializeRedisValueTuple1Internal<T, decimal>(await ExecuteScalarAsync(key, (c, k) => c.Value.ZRangeBytesByScoreWithScoresAsync(k, min, max, offset, count)));
1157 
1158         /// <summary>
1159         /// 返回有序集合中指定成员的索引
1160         /// </summary>
1161         /// <param name="key">不含prefix前辍</param>
1162         /// <param name="member">成员</param>
1163         /// <returns></returns>
1164         public Task<long?> ZRankAsync(string key, object member)
1165         {
1166             var args = this.SerializeRedisValueInternal(member);
1167             return ExecuteScalarAsync(key, (c, k) => c.Value.ZRankAsync(k, args));
1168         }
1169         /// <summary>
1170         /// 移除有序集合中的一个或多个成员
1171         /// </summary>
1172         /// <param name="key">不含prefix前辍</param>
1173         /// <param name="member">一个或多个成员</param>
1174         /// <returns></returns>
1175         async public Task<long> ZRemAsync<T>(string key, params T[] member)
1176         {
1177             if (member == null || member.Any() == false) return 0;
1178             var args = member.Select(z => this.SerializeRedisValueInternal(z)).ToArray();
1179             return await ExecuteScalarAsync(key, (c, k) => c.Value.ZRemAsync(k, args));
1180         }
1181         /// <summary>
1182         /// 移除有序集合中给定的排名区间的所有成员
1183         /// </summary>
1184         /// <param name="key">不含prefix前辍</param>
1185         /// <param name="start">开始位置,0表示第一个元素,-1表示最后一个元素</param>
1186         /// <param name="stop">结束位置,0表示第一个元素,-1表示最后一个元素</param>
1187         /// <returns></returns>
1188         public Task<long> ZRemRangeByRankAsync(string key, long start, long stop) => ExecuteScalarAsync(key, (c, k) => c.Value.ZRemRangeByRankAsync(k, start, stop));
1189         /// <summary>
1190         /// 移除有序集合中给定的分数区间的所有成员
1191         /// </summary>
1192         /// <param name="key">不含prefix前辍</param>
1193         /// <param name="min">分数最小值 decimal.MinValue 1</param>
1194         /// <param name="max">分数最大值 decimal.MaxValue 10</param>
1195         /// <returns></returns>
1196         public Task<long> ZRemRangeByScoreAsync(string key, decimal min, decimal max) => ExecuteScalarAsync(key, (c, k) => c.Value.ZRemRangeByScoreAsync(k, min == decimal.MinValue ? "-inf" : min.ToString(), max == decimal.MaxValue ? "+inf" : max.ToString()));
1197         /// <summary>
1198         /// 移除有序集合中给定的分数区间的所有成员
1199         /// </summary>
1200         /// <param name="key">不含prefix前辍</param>
1201         /// <param name="min">分数最小值 -inf (1 1</param>
1202         /// <param name="max">分数最大值 +inf (10 10</param>
1203         /// <returns></returns>
1204         public Task<long> ZRemRangeByScoreAsync(string key, string min, string max) => ExecuteScalarAsync(key, (c, k) => c.Value.ZRemRangeByScoreAsync(k, min, max));
1205 
1206         /// <summary>
1207         /// 返回有序集中指定区间内的成员,通过索引,分数从高到底
1208         /// </summary>
1209         /// <param name="key">不含prefix前辍</param>
1210         /// <param name="start">开始位置,0表示第一个元素,-1表示最后一个元素</param>
1211         /// <param name="stop">结束位置,0表示第一个元素,-1表示最后一个元素</param>
1212         /// <returns></returns>
1213         public Task<string[]> ZRevRangeAsync(string key, long start, long stop) => ExecuteScalarAsync(key, (c, k) => c.Value.ZRevRangeAsync(k, start, stop, false));
1214         /// <summary>
1215         /// 返回有序集中指定区间内的成员,通过索引,分数从高到底
1216         /// </summary>
1217         /// <typeparam name="T">byte[] 或其他类型</typeparam>
1218         /// <param name="key">不含prefix前辍</param>
1219         /// <param name="start">开始位置,0表示第一个元素,-1表示最后一个元素</param>
1220         /// <param name="stop">结束位置,0表示第一个元素,-1表示最后一个元素</param>
1221         /// <returns></returns>
1222         async public Task<T[]> ZRevRangeAsync<T>(string key, long start, long stop) => this.DeserializeRedisValueArrayInternal<T>(await ExecuteScalarAsync(key, (c, k) => c.Value.ZRevRangeBytesAsync(k, start, stop, false)));
1223         /// <summary>
1224         /// 返回有序集中指定区间内的成员和分数,通过索引,分数从高到底
1225         /// </summary>
1226         /// <param name="key">不含prefix前辍</param>
1227         /// <param name="start">开始位置,0表示第一个元素,-1表示最后一个元素</param>
1228         /// <param name="stop">结束位置,0表示第一个元素,-1表示最后一个元素</param>
1229         /// <returns></returns>
1230         async public Task<(string member, decimal score)[]> ZRevRangeWithScoresAsync(string key, long start, long stop) => (await ExecuteScalarAsync(key, (c, k) => c.Value.ZRevRangeWithScoresAsync(k, start, stop))).Select(a => (a.Item1, a.Item2)).ToArray();
1231         /// <summary>
1232         /// 返回有序集中指定区间内的成员和分数,通过索引,分数从高到底
1233         /// </summary>
1234         /// <typeparam name="T">byte[] 或其他类型</typeparam>
1235         /// <param name="key">不含prefix前辍</param>
1236         /// <param name="start">开始位置,0表示第一个元素,-1表示最后一个元素</param>
1237         /// <param name="stop">结束位置,0表示第一个元素,-1表示最后一个元素</param>
1238         /// <returns></returns>
1239         async public Task<(T member, decimal score)[]> ZRevRangeWithScoresAsync<T>(string key, long start, long stop) => this.DeserializeRedisValueTuple1Internal<T, decimal>(await ExecuteScalarAsync(key, (c, k) => c.Value.ZRevRangeBytesWithScoresAsync(k, start, stop)));
1240 
1241         /// <summary>
1242         /// 返回有序集中指定分数区间内的成员,分数从高到低排序
1243         /// </summary>
1244         /// <param name="key">不含prefix前辍</param>
1245         /// <param name="max">分数最大值 decimal.MaxValue 10</param>
1246         /// <param name="min">分数最小值 decimal.MinValue 1</param>
1247         /// <param name="count">返回多少成员</param>
1248         /// <param name="offset">返回条件偏移位置</param>
1249         /// <returns></returns>
1250         public Task<string[]> ZRevRangeByScoreAsync(string key, decimal max, decimal min, long? count = null, long? offset = 0) => ExecuteScalarAsync(key, (c, k) => c.Value.ZRevRangeByScoreAsync(k, max == decimal.MaxValue ? "+inf" : max.ToString(), min == decimal.MinValue ? "-inf" : min.ToString(), false, offset, count));
1251         /// <summary>
1252         /// 返回有序集中指定分数区间内的成员,分数从高到低排序
1253         /// </summary>
1254         /// <typeparam name="T">byte[] 或其他类型</typeparam>
1255         /// <param name="key">不含prefix前辍</param>
1256         /// <param name="max">分数最大值 decimal.MaxValue 10</param>
1257         /// <param name="min">分数最小值 decimal.MinValue 1</param>
1258         /// <param name="count">返回多少成员</param>
1259         /// <param name="offset">返回条件偏移位置</param>
1260         /// <returns></returns>
1261         async public Task<T[]> ZRevRangeByScoreAsync<T>(string key, decimal max, decimal min, long? count = null, long offset = 0) =>
1262             this.DeserializeRedisValueArrayInternal<T>(await ExecuteScalarAsync(key, (c, k) => c.Value.ZRevRangeBytesByScoreAsync(k, max == decimal.MaxValue ? "+inf" : max.ToString(), min == decimal.MinValue ? "-inf" : min.ToString(), false, offset, count)));
1263         /// <summary>
1264         /// 返回有序集中指定分数区间内的成员,分数从高到低排序
1265         /// </summary>
1266         /// <param name="key">不含prefix前辍</param>
1267         /// <param name="max">分数最大值 +inf (10 10</param>
1268         /// <param name="min">分数最小值 -inf (1 1</param>
1269         /// <param name="count">返回多少成员</param>
1270         /// <param name="offset">返回条件偏移位置</param>
1271         /// <returns></returns>
1272         public Task<string[]> ZRevRangeByScoreAsync(string key, string max, string min, long? count = null, long? offset = 0) => ExecuteScalarAsync(key, (c, k) => c.Value.ZRevRangeByScoreAsync(k, max, min, false, offset, count));
1273         /// <summary>
1274         /// 返回有序集中指定分数区间内的成员,分数从高到低排序
1275         /// </summary>
1276         /// <typeparam name="T">byte[] 或其他类型</typeparam>
1277         /// <param name="key">不含prefix前辍</param>
1278         /// <param name="max">分数最大值 +inf (10 10</param>
1279         /// <param name="min">分数最小值 -inf (1 1</param>
1280         /// <param name="count">返回多少成员</param>
1281         /// <param name="offset">返回条件偏移位置</param>
1282         /// <returns></returns>
1283         async public Task<T[]> ZRevRangeByScoreAsync<T>(string key, string max, string min, long? count = null, long offset = 0) =>
1284             this.DeserializeRedisValueArrayInternal<T>(await ExecuteScalarAsync(key, (c, k) => c.Value.ZRevRangeBytesByScoreAsync(k, max, min, false, offset, count)));
1285 
1286         /// <summary>
1287         /// 返回有序集中指定分数区间内的成员和分数,分数从高到低排序
1288         /// </summary>
1289         /// <param name="key">不含prefix前辍</param>
1290         /// <param name="max">分数最大值 decimal.MaxValue 10</param>
1291         /// <param name="min">分数最小值 decimal.MinValue 1</param>
1292         /// <param name="count">返回多少成员</param>
1293         /// <param name="offset">返回条件偏移位置</param>
1294         /// <returns></returns>
1295         async public Task<(string member, decimal score)[]> ZRevRangeByScoreWithScoresAsync(string key, decimal max, decimal min, long? count = null, long offset = 0) =>
1296             (await ExecuteScalarAsync(key, (c, k) => c.Value.ZRevRangeByScoreWithScoresAsync(k, max == decimal.MaxValue ? "+inf" : max.ToString(), min == decimal.MinValue ? "-inf" : min.ToString(), offset, count))).Select(z => (z.Item1, z.Item2)).ToArray();
1297         /// <summary>
1298         /// 返回有序集中指定分数区间内的成员和分数,分数从高到低排序
1299         /// </summary>
1300         /// <typeparam name="T">byte[] 或其他类型</typeparam>
1301         /// <param name="key">不含prefix前辍</param>
1302         /// <param name="max">分数最大值 decimal.MaxValue 10</param>
1303         /// <param name="min">分数最小值 decimal.MinValue 1</param>
1304         /// <param name="count">返回多少成员</param>
1305         /// <param name="offset">返回条件偏移位置</param>
1306         /// <returns></returns>
1307         async public Task<(T member, decimal score)[]> ZRevRangeByScoreWithScoresAsync<T>(string key, decimal max, decimal min, long? count = null, long offset = 0) =>
1308             this.DeserializeRedisValueTuple1Internal<T, decimal>(await ExecuteScalarAsync(key, (c, k) => c.Value.ZRevRangeBytesByScoreWithScoresAsync(k, max == decimal.MaxValue ? "+inf" : max.ToString(), min == decimal.MinValue ? "-inf" : min.ToString(), offset, count)));
1309         /// <summary>
1310         /// 返回有序集中指定分数区间内的成员和分数,分数从高到低排序
1311         /// </summary>
1312         /// <param name="key">不含prefix前辍</param>
1313         /// <param name="max">分数最大值 +inf (10 10</param>
1314         /// <param name="min">分数最小值 -inf (1 1</param>
1315         /// <param name="count">返回多少成员</param>
1316         /// <param name="offset">返回条件偏移位置</param>
1317         /// <returns></returns>
1318         async public Task<(string member, decimal score)[]> ZRevRangeByScoreWithScoresAsync(string key, string max, string min, long? count = null, long offset = 0) =>
1319             (await ExecuteScalarAsync(key, (c, k) => c.Value.ZRevRangeByScoreWithScoresAsync(k, max, min, offset, count))).Select(z => (z.Item1, z.Item2)).ToArray();
1320         /// <summary>
1321         /// 返回有序集中指定分数区间内的成员和分数,分数从高到低排序
1322         /// </summary>
1323         /// <typeparam name="T">byte[] 或其他类型</typeparam>
1324         /// <param name="key">不含prefix前辍</param>
1325         /// <param name="max">分数最大值 +inf (10 10</param>
1326         /// <param name="min">分数最小值 -inf (1 1</param>
1327         /// <param name="count">返回多少成员</param>
1328         /// <param name="offset">返回条件偏移位置</param>
1329         /// <returns></returns>
1330         async public Task<(T member, decimal score)[]> ZRevRangeByScoreWithScoresAsync<T>(string key, string max, string min, long? count = null, long offset = 0) =>
1331             this.DeserializeRedisValueTuple1Internal<T, decimal>(await ExecuteScalarAsync(key, (c, k) => c.Value.ZRevRangeBytesByScoreWithScoresAsync(k, max, min, offset, count)));
1332 
1333         /// <summary>
1334         /// 返回有序集合中指定成员的排名,有序集成员按分数值递减(从大到小)排序
1335         /// </summary>
1336         /// <param name="key">不含prefix前辍</param>
1337         /// <param name="member">成员</param>
1338         /// <returns></returns>
1339         public Task<long?> ZRevRankAsync(string key, object member)
1340         {
1341             var args = this.SerializeRedisValueInternal(member);
1342             return ExecuteScalarAsync(key, (c, k) => c.Value.ZRevRankAsync(k, args));
1343         }
1344         /// <summary>
1345         /// 返回有序集中,成员的分数值
1346         /// </summary>
1347         /// <param name="key">不含prefix前辍</param>
1348         /// <param name="member">成员</param>
1349         /// <returns></returns>
1350         public Task<decimal?> ZScoreAsync(string key, object member)
1351         {
1352             var args = this.SerializeRedisValueInternal(member);
1353             return ExecuteScalarAsync(key, (c, k) => c.Value.ZScoreAsync(k, args));
1354         }
1355 
1356         /// <summary>
1357         /// 计算给定的一个或多个有序集的并集,将结果集存储在新的有序集合 destination 中
1358         /// </summary>
1359         /// <param name="destination">新的有序集合,不含prefix前辍</param>
1360         /// <param name="weights">使用 WEIGHTS 选项,你可以为 每个 给定有序集 分别 指定一个乘法因子。如果没有指定 WEIGHTS 选项,乘法因子默认设置为 1 。</param>
1361         /// <param name="aggregate">Sum | Min | Max</param>
1362         /// <param name="keys">一个或多个有序集合,不含prefix前辍</param>
1363         /// <returns></returns>
1364         public Task<long> ZUnionStoreAsync(string destination, decimal[] weights, RedisAggregate aggregate, params string[] keys)
1365         {
1366             if (keys == null || keys.Length == 0) throw new Exception("keys 参数不可为空");
1367             if (weights != null && weights.Length != keys.Length) throw new Exception("weights 和 keys 参数长度必须相同");
1368             return NodesNotSupportAsync(new[] { destination }.Concat(keys).ToArray(), 0, (c, k) => c.Value.ZUnionStoreAsync(k.First(), weights, aggregate, k.Skip(1).ToArray()));
1369         }
1370 
1371         /// <summary>
1372         /// 迭代有序集合中的元素
1373         /// </summary>
1374         /// <param name="key">不含prefix前辍</param>
1375         /// <param name="cursor">位置</param>
1376         /// <param name="pattern">模式</param>
1377         /// <param name="count">数量</param>
1378         /// <returns></returns>
1379         async public Task<RedisScan<(string member, decimal score)>> ZScanAsync(string key, long cursor, string pattern = null, long? count = null)
1380         {
1381             var scan = await ExecuteScalarAsync(key, (c, k) => c.Value.ZScanAsync(k, cursor, pattern, count));
1382             return new RedisScan<(string, decimal)>(scan.Cursor, scan.Items.Select(z => (z.Item1, z.Item2)).ToArray());
1383         }
1384         /// <summary>
1385         /// 迭代有序集合中的元素
1386         /// </summary>
1387         /// <typeparam name="T">byte[] 或其他类型</typeparam>
1388         /// <param name="key">不含prefix前辍</param>
1389         /// <param name="cursor">位置</param>
1390         /// <param name="pattern">模式</param>
1391         /// <param name="count">数量</param>
1392         /// <returns></returns>
1393         async public Task<RedisScan<(T member, decimal score)>> ZScanAsync<T>(string key, long cursor, string pattern = null, long? count = null)
1394         {
1395             var scan = await ExecuteScalarAsync(key, (c, k) => c.Value.ZScanBytesAsync(k, cursor, pattern, count));
1396             return new RedisScan<(T, decimal)>(scan.Cursor, this.DeserializeRedisValueTuple1Internal<T, decimal>(scan.Items));
1397         }
1398 
1399         /// <summary>
1400         /// 当有序集合的所有成员都具有相同的分值时,有序集合的元素会根据成员的字典序来进行排序,这个命令可以返回给定的有序集合键 key 中,值介于 min 和 max 之间的成员。
1401         /// </summary>
1402         /// <param name="key">不含prefix前辍</param>
1403         /// <param name="min">'(' 表示包含在范围,'[' 表示不包含在范围,'+' 正无穷大,'-' 负无限。 ZRANGEBYLEX zset - + ,命令将返回有序集合中的所有元素</param>
1404         /// <param name="max">'(' 表示包含在范围,'[' 表示不包含在范围,'+' 正无穷大,'-' 负无限。 ZRANGEBYLEX zset - + ,命令将返回有序集合中的所有元素</param>
1405         /// <param name="count">返回多少成员</param>
1406         /// <param name="offset">返回条件偏移位置</param>
1407         /// <returns></returns>
1408         public Task<string[]> ZRangeByLexAsync(string key, string min, string max, long? count = null, long offset = 0) =>
1409             ExecuteScalarAsync(key, (c, k) => c.Value.ZRangeByLexAsync(k, min, max, offset, count));
1410         /// <summary>
1411         /// 当有序集合的所有成员都具有相同的分值时,有序集合的元素会根据成员的字典序来进行排序,这个命令可以返回给定的有序集合键 key 中,值介于 min 和 max 之间的成员。
1412         /// </summary>
1413         /// <typeparam name="T">byte[] 或其他类型</typeparam>
1414         /// <param name="key">不含prefix前辍</param>
1415         /// <param name="min">'(' 表示包含在范围,'[' 表示不包含在范围,'+' 正无穷大,'-' 负无限。 ZRANGEBYLEX zset - + ,命令将返回有序集合中的所有元素</param>
1416         /// <param name="max">'(' 表示包含在范围,'[' 表示不包含在范围,'+' 正无穷大,'-' 负无限。 ZRANGEBYLEX zset - + ,命令将返回有序集合中的所有元素</param>
1417         /// <param name="count">返回多少成员</param>
1418         /// <param name="offset">返回条件偏移位置</param>
1419         /// <returns></returns>
1420         async public Task<T[]> ZRangeByLexAsync<T>(string key, string min, string max, long? count = null, long offset = 0) =>
1421             this.DeserializeRedisValueArrayInternal<T>(await ExecuteScalarAsync(key, (c, k) => c.Value.ZRangeBytesByLexAsync(k, min, max, offset, count)));
1422 
1423         /// <summary>
1424         /// 当有序集合的所有成员都具有相同的分值时,有序集合的元素会根据成员的字典序来进行排序,这个命令可以返回给定的有序集合键 key 中,值介于 min 和 max 之间的成员。
1425         /// </summary>
1426         /// <param name="key">不含prefix前辍</param>
1427         /// <param name="min">'(' 表示包含在范围,'[' 表示不包含在范围,'+' 正无穷大,'-' 负无限。 ZRANGEBYLEX zset - + ,命令将返回有序集合中的所有元素</param>
1428         /// <param name="max">'(' 表示包含在范围,'[' 表示不包含在范围,'+' 正无穷大,'-' 负无限。 ZRANGEBYLEX zset - + ,命令将返回有序集合中的所有元素</param>
1429         /// <returns></returns>
1430         public Task<long> ZRemRangeByLexAsync(string key, string min, string max) =>
1431             ExecuteScalarAsync(key, (c, k) => c.Value.ZRemRangeByLexAsync(k, min, max));
1432         /// <summary>
1433         /// 当有序集合的所有成员都具有相同的分值时,有序集合的元素会根据成员的字典序来进行排序,这个命令可以返回给定的有序集合键 key 中,值介于 min 和 max 之间的成员。
1434         /// </summary>
1435         /// <param name="key">不含prefix前辍</param>
1436         /// <param name="min">'(' 表示包含在范围,'[' 表示不包含在范围,'+' 正无穷大,'-' 负无限。 ZRANGEBYLEX zset - + ,命令将返回有序集合中的所有元素</param>
1437         /// <param name="max">'(' 表示包含在范围,'[' 表示不包含在范围,'+' 正无穷大,'-' 负无限。 ZRANGEBYLEX zset - + ,命令将返回有序集合中的所有元素</param>
1438         /// <returns></returns>
1439         public Task<long> ZLexCountAsync(string key, string min, string max) =>
1440             ExecuteScalarAsync(key, (c, k) => c.Value.ZLexCountAsync(k, min, max));
1441         #endregion
1442 
1443         #region Set
1444         /// <summary>
1445         /// 向集合添加一个或多个成员
1446         /// </summary>
1447         /// <param name="key">不含prefix前辍</param>
1448         /// <param name="members">一个或多个成员</param>
1449         /// <returns></returns>
1450         async public Task<long> SAddAsync<T>(string key, params T[] members)
1451         {
1452             if (members == null || members.Any() == false) return 0;
1453             var args = members.Select(z => this.SerializeRedisValueInternal(z)).ToArray();
1454             return await ExecuteScalarAsync(key, (c, k) => c.Value.SAddAsync(k, args));
1455         }
1456         /// <summary>
1457         /// 获取集合的成员数
1458         /// </summary>
1459         /// <param name="key">不含prefix前辍</param>
1460         /// <returns></returns>
1461         public Task<long> SCardAsync(string key) => ExecuteScalarAsync(key, (c, k) => c.Value.SCardAsync(k));
1462         /// <summary>
1463         /// 返回给定所有集合的差集
1464         /// </summary>
1465         /// <param name="keys">不含prefix前辍</param>
1466         /// <returns></returns>
1467         public Task<string[]> SDiffAsync(params string[] keys) => NodesNotSupportAsync(keys, new string[0], (c, k) => c.Value.SDiffAsync(k));
1468         /// <summary>
1469         /// 返回给定所有集合的差集
1470         /// </summary>
1471         /// <typeparam name="T">byte[] 或其他类型</typeparam>
1472         /// <param name="keys">不含prefix前辍</param>
1473         /// <returns></returns>
1474         async public Task<T[]> SDiffAsync<T>(params string[] keys) => this.DeserializeRedisValueArrayInternal<T>(await NodesNotSupportAsync(keys, new byte[0][], (c, k) => c.Value.SDiffBytesAsync(k)));
1475         /// <summary>
1476         /// 返回给定所有集合的差集并存储在 destination 中
1477         /// </summary>
1478         /// <param name="destination">新的无序集合,不含prefix前辍</param>
1479         /// <param name="keys">一个或多个无序集合,不含prefix前辍</param>
1480         /// <returns></returns>
1481         public Task<long> SDiffStoreAsync(string destination, params string[] keys) => NodesNotSupportAsync(new[] { destination }.Concat(keys).ToArray(), 0, (c, k) => c.Value.SDiffStoreAsync(k.First(), k.Skip(1).ToArray()));
1482         /// <summary>
1483         /// 返回给定所有集合的交集
1484         /// </summary>
1485         /// <param name="keys">不含prefix前辍</param>
1486         /// <returns></returns>
1487         public Task<string[]> SInterAsync(params string[] keys) => NodesNotSupportAsync(keys, new string[0], (c, k) => c.Value.SInterAsync(k));
1488         /// <summary>
1489         /// 返回给定所有集合的交集
1490         /// </summary>
1491         /// <typeparam name="T">byte[] 或其他类型</typeparam>
1492         /// <param name="keys">不含prefix前辍</param>
1493         /// <returns></returns>
1494         async public Task<T[]> SInterAsync<T>(params string[] keys) => this.DeserializeRedisValueArrayInternal<T>(await NodesNotSupportAsync(keys, new byte[0][], (c, k) => c.Value.SInterBytesAsync(k)));
1495         /// <summary>
1496         /// 返回给定所有集合的交集并存储在 destination 中
1497         /// </summary>
1498         /// <param name="destination">新的无序集合,不含prefix前辍</param>
1499         /// <param name="keys">一个或多个无序集合,不含prefix前辍</param>
1500         /// <returns></returns>
1501         public Task<long> SInterStoreAsync(string destination, params string[] keys) => NodesNotSupportAsync(new[] { destination }.Concat(keys).ToArray(), 0, (c, k) => c.Value.SInterStoreAsync(k.First(), k.Skip(1).ToArray()));
1502         /// <summary>
1503         /// 判断 member 元素是否是集合 key 的成员
1504         /// </summary>
1505         /// <param name="key">不含prefix前辍</param>
1506         /// <param name="member">成员</param>
1507         /// <returns></returns>
1508         public Task<bool> SIsMemberAsync(string key, object member)
1509         {
1510             var args = this.SerializeRedisValueInternal(member);
1511             return ExecuteScalarAsync(key, (c, k) => c.Value.SIsMemberAsync(k, args));
1512         }
1513         /// <summary>
1514         /// 返回集合中的所有成员
1515         /// </summary>
1516         /// <param name="key">不含prefix前辍</param>
1517         /// <returns></returns>
1518         public Task<string[]> SMembersAsync(string key) => ExecuteScalarAsync(key, (c, k) => c.Value.SMembersAsync(k));
1519         /// <summary>
1520         /// 返回集合中的所有成员
1521         /// </summary>
1522         /// <typeparam name="T">byte[] 或其他类型</typeparam>
1523         /// <param name="key">不含prefix前辍</param>
1524         /// <returns></returns>
1525         async public Task<T[]> SMembersAsync<T>(string key) => this.DeserializeRedisValueArrayInternal<T>(await ExecuteScalarAsync(key, (c, k) => c.Value.SMembersBytesAsync(k)));
1526         /// <summary>
1527         /// 将 member 元素从 source 集合移动到 destination 集合
1528         /// </summary>
1529         /// <param name="source">无序集合key,不含prefix前辍</param>
1530         /// <param name="destination">目标无序集合key,不含prefix前辍</param>
1531         /// <param name="member">成员</param>
1532         /// <returns></returns>
1533         async public Task<bool> SMoveAsync(string source, string destination, object member)
1534         {
1535             string rule = string.Empty;
1536             if (Nodes.Count > 1)
1537             {
1538                 var rule1 = NodeRuleRaw(source);
1539                 var rule2 = NodeRuleRaw(destination);
1540                 if (rule1 != rule2)
1541                 {
1542                     if (await SRemAsync(source, member) <= 0) return false;
1543                     return await SAddAsync(destination, member) > 0;
1544                 }
1545                 rule = rule1;
1546             }
1547             var pool = Nodes.TryGetValue(rule, out var b) ? b : Nodes.First().Value;
1548             var key1 = string.Concat(pool.Prefix, source);
1549             var key2 = string.Concat(pool.Prefix, destination);
1550             var args = this.SerializeRedisValueInternal(member);
1551             return await GetAndExecuteAsync(pool, conn => conn.Value.SMoveAsync(key1, key2, args));
1552         }
1553         /// <summary>
1554         /// 移除并返回集合中的一个随机元素
1555         /// </summary>
1556         /// <param name="key">不含prefix前辍</param>
1557         /// <returns></returns>
1558         public Task<string> SPopAsync(string key) => ExecuteScalarAsync(key, (c, k) => c.Value.SPopAsync(k));
1559         /// <summary>
1560         /// 移除并返回集合中的一个随机元素
1561         /// </summary>
1562         /// <typeparam name="T">byte[] 或其他类型</typeparam>
1563         /// <param name="key">不含prefix前辍</param>
1564         /// <returns></returns>
1565         async public Task<T> SPopAsync<T>(string key) => this.DeserializeRedisValueInternal<T>(await ExecuteScalarAsync(key, (c, k) => c.Value.SPopBytesAsync(k)));
1566         /// <summary>
1567         /// [redis-server 3.2] 移除并返回集合中的一个或多个随机元素
1568         /// </summary>
1569         /// <param name="key">不含prefix前辍</param>
1570         /// <param name="count">移除并返回的个数</param>
1571         /// <returns></returns>
1572         public Task<string[]> SPopAsync(string key, long count) => ExecuteScalarAsync(key, (c, k) => c.Value.SPopAsync(k, count));
1573         /// <summary>
1574         /// [redis-server 3.2] 移除并返回集合中的一个或多个随机元素
1575         /// </summary>
1576         /// <typeparam name="T">byte[] 或其他类型</typeparam>
1577         /// <param name="key">不含prefix前辍</param>
1578         /// <param name="count">移除并返回的个数</param>
1579         /// <returns></returns>
1580         async public Task<T[]> SPopAsync<T>(string key, long count) => this.DeserializeRedisValueArrayInternal<T>(await ExecuteScalarAsync(key, (c, k) => c.Value.SPopBytesAsync(k, count)));
1581         /// <summary>
1582         /// 返回集合中的一个随机元素
1583         /// </summary>
1584         /// <param name="key">不含prefix前辍</param>
1585         /// <returns></returns>
1586         public Task<string> SRandMemberAsync(string key) => ExecuteScalarAsync(key, (c, k) => c.Value.SRandMemberAsync(k));
1587         /// <summary>
1588         /// 返回集合中的一个随机元素
1589         /// </summary>
1590         /// <typeparam name="T">byte[] 或其他类型</typeparam>
1591         /// <param name="key">不含prefix前辍</param>
1592         /// <returns></returns>
1593         async public Task<T> SRandMemberAsync<T>(string key) => this.DeserializeRedisValueInternal<T>(await ExecuteScalarAsync(key, (c, k) => c.Value.SRandMemberBytesAsync(k)));
1594         /// <summary>
1595         /// 返回集合中一个或多个随机数的元素
1596         /// </summary>
1597         /// <param name="key">不含prefix前辍</param>
1598         /// <param name="count">返回个数</param>
1599         /// <returns></returns>
1600         public Task<string[]> SRandMembersAsync(string key, int count = 1) => ExecuteScalarAsync(key, (c, k) => c.Value.SRandMembersAsync(k, count));
1601         /// <summary>
1602         /// 返回集合中一个或多个随机数的元素
1603         /// </summary>
1604         /// <typeparam name="T">byte[] 或其他类型</typeparam>
1605         /// <param name="key">不含prefix前辍</param>
1606         /// <param name="count">返回个数</param>
1607         /// <returns></returns>
1608         async public Task<T[]> SRandMembersAsync<T>(string key, int count = 1) => this.DeserializeRedisValueArrayInternal<T>(await ExecuteScalarAsync(key, (c, k) => c.Value.SRandMembersBytesAsync(k, count)));
1609         /// <summary>
1610         /// 移除集合中一个或多个成员
1611         /// </summary>
1612         /// <param name="key">不含prefix前辍</param>
1613         /// <param name="members">一个或多个成员</param>
1614         /// <returns></returns>
1615         async public Task<long> SRemAsync<T>(string key, params T[] members)
1616         {
1617             if (members == null || members.Any() == false) return 0;
1618             var args = members.Select(z => this.SerializeRedisValueInternal(z)).ToArray();
1619             return await ExecuteScalarAsync(key, (c, k) => c.Value.SRemAsync(k, args));
1620         }
1621         /// <summary>
1622         /// 返回所有给定集合的并集
1623         /// </summary>
1624         /// <param name="keys">不含prefix前辍</param>
1625         /// <returns></returns>
1626         public Task<string[]> SUnionAsync(params string[] keys) => NodesNotSupportAsync(keys, new string[0], (c, k) => c.Value.SUnionAsync(k));
1627         /// <summary>
1628         /// 返回所有给定集合的并集
1629         /// </summary>
1630         /// <typeparam name="T">byte[] 或其他类型</typeparam>
1631         /// <param name="keys">不含prefix前辍</param>
1632         /// <returns></returns>
1633         async public Task<T[]> SUnionAsync<T>(params string[] keys) => this.DeserializeRedisValueArrayInternal<T>(await NodesNotSupportAsync(keys, new byte[0][], (c, k) => c.Value.SUnionBytesAsync(k)));
1634         /// <summary>
1635         /// 所有给定集合的并集存储在 destination 集合中
1636         /// </summary>
1637         /// <param name="destination">新的无序集合,不含prefix前辍</param>
1638         /// <param name="keys">一个或多个无序集合,不含prefix前辍</param>
1639         /// <returns></returns>
1640         public Task<long> SUnionStoreAsync(string destination, params string[] keys) => NodesNotSupportAsync(new[] { destination }.Concat(keys).ToArray(), 0, (c, k) => c.Value.SUnionStoreAsync(k.First(), k.Skip(1).ToArray()));
1641         /// <summary>
1642         /// 迭代集合中的元素
1643         /// </summary>
1644         /// <param name="key">不含prefix前辍</param>
1645         /// <param name="cursor">位置</param>
1646         /// <param name="pattern">模式</param>
1647         /// <param name="count">数量</param>
1648         /// <returns></returns>
1649         public Task<RedisScan<string>> SScanAsync(string key, long cursor, string pattern = null, long? count = null) => ExecuteScalarAsync(key, (c, k) => c.Value.SScanAsync(k, cursor, pattern, count));
1650         /// <summary>
1651         /// 迭代集合中的元素
1652         /// </summary>
1653         /// <typeparam name="T">byte[] 或其他类型</typeparam>
1654         /// <param name="key">不含prefix前辍</param>
1655         /// <param name="cursor">位置</param>
1656         /// <param name="pattern">模式</param>
1657         /// <param name="count">数量</param>
1658         /// <returns></returns>
1659         async public Task<RedisScan<T>> SScanAsync<T>(string key, long cursor, string pattern = null, long? count = null)
1660         {
1661             var scan = await ExecuteScalarAsync(key, (c, k) => c.Value.SScanBytesAsync(k, cursor, pattern, count));
1662             return new RedisScan<T>(scan.Cursor, this.DeserializeRedisValueArrayInternal<T>(scan.Items));
1663         }
1664         #endregion
1665 
1666         #region List
1667         /// <summary>
1668         /// 通过索引获取列表中的元素
1669         /// </summary>
1670         /// <param name="key">不含prefix前辍</param>
1671         /// <param name="index">索引</param>
1672         /// <returns></returns>
1673         public Task<string> LIndexAsync(string key, long index) => ExecuteScalarAsync(key, (c, k) => c.Value.LIndexAsync(k, index));
1674         /// <summary>
1675         /// 通过索引获取列表中的元素
1676         /// </summary>
1677         /// <typeparam name="T">byte[] 或其他类型</typeparam>
1678         /// <param name="key">不含prefix前辍</param>
1679         /// <param name="index">索引</param>
1680         /// <returns></returns>
1681         async public Task<T> LIndexAsync<T>(string key, long index) => this.DeserializeRedisValueInternal<T>(await ExecuteScalarAsync(key, (c, k) => c.Value.LIndexBytesAsync(k, index)));
1682         /// <summary>
1683         /// 在列表中的元素前面插入元素
1684         /// </summary>
1685         /// <param name="key">不含prefix前辍</param>
1686         /// <param name="pivot">列表的元素</param>
1687         /// <param name="value">新元素</param>
1688         /// <returns></returns>
1689         public Task<long> LInsertBeforeAsync(string key, object pivot, object value)
1690         {
1691             var args = this.SerializeRedisValueInternal(value);
1692             return ExecuteScalarAsync(key, (c, k) => c.Value.LInsertAsync(k, RedisInsert.Before, pivot, args));
1693         }
1694         /// <summary>
1695         /// 在列表中的元素后面插入元素
1696         /// </summary>
1697         /// <param name="key">不含prefix前辍</param>
1698         /// <param name="pivot">列表的元素</param>
1699         /// <param name="value">新元素</param>
1700         /// <returns></returns>
1701         public Task<long> LInsertAfterAsync(string key, object pivot, object value)
1702         {
1703             var args = this.SerializeRedisValueInternal(value);
1704             return ExecuteScalarAsync(key, (c, k) => c.Value.LInsertAsync(k, RedisInsert.After, pivot, args));
1705         }
1706         /// <summary>
1707         /// 获取列表长度
1708         /// </summary>
1709         /// <param name="key">不含prefix前辍</param>
1710         /// <returns></returns>
1711         public Task<long> LLenAsync(string key) => ExecuteScalarAsync(key, (c, k) => c.Value.LLenAsync(k));
1712         /// <summary>
1713         /// 移出并获取列表的第一个元素
1714         /// </summary>
1715         /// <param name="key">不含prefix前辍</param>
1716         /// <returns></returns>
1717         public Task<string> LPopAsync(string key) => ExecuteScalarAsync(key, (c, k) => c.Value.LPopAsync(k));
1718         /// <summary>
1719         /// 移出并获取列表的第一个元素
1720         /// </summary>
1721         /// <typeparam name="T">byte[] 或其他类型</typeparam>
1722         /// <param name="key">不含prefix前辍</param>
1723         /// <returns></returns>
1724         async public Task<T> LPopAsync<T>(string key) => this.DeserializeRedisValueInternal<T>(await ExecuteScalarAsync(key, (c, k) => c.Value.LPopBytesAsync(k)));
1725         /// <summary>
1726         /// 将一个或多个值插入到列表头部
1727         /// </summary>
1728         /// <param name="key">不含prefix前辍</param>
1729         /// <param name="value">一个或多个值</param>
1730         /// <returns>执行 LPUSH 命令后,列表的长度</returns>
1731         async public Task<long> LPushAsync<T>(string key, params T[] value)
1732         {
1733             if (value == null || value.Any() == false) return 0;
1734             var args = value.Select(z => this.SerializeRedisValueInternal(z)).ToArray();
1735             return await ExecuteScalarAsync(key, (c, k) => c.Value.LPushAsync(k, args));
1736         }
1737         /// <summary>
1738         /// 将一个值插入到已存在的列表头部
1739         /// </summary>
1740         /// <param name="key">不含prefix前辍</param>
1741         /// <param name="value"></param>
1742         /// <returns>执行 LPUSHX 命令后,列表的长度。</returns>
1743         public Task<long> LPushXAsync(string key, object value)
1744         {
1745             var args = this.SerializeRedisValueInternal(value);
1746             return ExecuteScalarAsync(key, (c, k) => c.Value.LPushXAsync(k, args));
1747         }
1748         /// <summary>
1749         /// 获取列表指定范围内的元素
1750         /// </summary>
1751         /// <param name="key">不含prefix前辍</param>
1752         /// <param name="start">开始位置,0表示第一个元素,-1表示最后一个元素</param>
1753         /// <param name="stop">结束位置,0表示第一个元素,-1表示最后一个元素</param>
1754         /// <returns></returns>
1755         public Task<string[]> LRangeAsync(string key, long start, long stop) => ExecuteScalarAsync(key, (c, k) => c.Value.LRangeAsync(k, start, stop));
1756         /// <summary>
1757         /// 获取列表指定范围内的元素
1758         /// </summary>
1759         /// <typeparam name="T">byte[] 或其他类型</typeparam>
1760         /// <param name="key">不含prefix前辍</param>
1761         /// <param name="start">开始位置,0表示第一个元素,-1表示最后一个元素</param>
1762         /// <param name="stop">结束位置,0表示第一个元素,-1表示最后一个元素</param>
1763         /// <returns></returns>
1764         async public Task<T[]> LRangeAsync<T>(string key, long start, long stop) => this.DeserializeRedisValueArrayInternal<T>(await ExecuteScalarAsync(key, (c, k) => c.Value.LRangeBytesAsync(k, start, stop)));
1765         /// <summary>
1766         /// 根据参数 count 的值,移除列表中与参数 value 相等的元素
1767         /// </summary>
1768         /// <param name="key">不含prefix前辍</param>
1769         /// <param name="count">移除的数量,大于0时从表头删除数量count,小于0时从表尾删除数量-count,等于0移除所有</param>
1770         /// <param name="value">元素</param>
1771         /// <returns></returns>
1772         public Task<long> LRemAsync(string key, long count, object value)
1773         {
1774             var args = this.SerializeRedisValueInternal(value);
1775             return ExecuteScalarAsync(key, (c, k) => c.Value.LRemAsync(k, count, args));
1776         }
1777         /// <summary>
1778         /// 通过索引设置列表元素的值
1779         /// </summary>
1780         /// <param name="key">不含prefix前辍</param>
1781         /// <param name="index">索引</param>
1782         /// <param name="value"></param>
1783         /// <returns></returns>
1784         async public Task<bool> LSetAsync(string key, long index, object value)
1785         {
1786             var args = this.SerializeRedisValueInternal(value);
1787             return await ExecuteScalar(key, (c, k) => c.Value.LSetAsync(k, index, args)) == "OK";
1788         }
1789         /// <summary>
1790         /// 对一个列表进行修剪,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除
1791         /// </summary>
1792         /// <param name="key">不含prefix前辍</param>
1793         /// <param name="start">开始位置,0表示第一个元素,-1表示最后一个元素</param>
1794         /// <param name="stop">结束位置,0表示第一个元素,-1表示最后一个元素</param>
1795         /// <returns></returns>
1796         public Task<bool> LTrimAsync(string key, long start, long stop) => ExecuteScalarAsync(key, async (c, k) => await c.Value.LTrimAsync(k, start, stop) == "OK");
1797         /// <summary>
1798         /// 移除并获取列表最后一个元素
1799         /// </summary>
1800         /// <param name="key">不含prefix前辍</param>
1801         /// <returns></returns>
1802         public Task<string> RPopAsync(string key) => ExecuteScalarAsync(key, (c, k) => c.Value.RPopAsync(k));
1803         /// <summary>
1804         /// 移除并获取列表最后一个元素
1805         /// </summary>
1806         /// <typeparam name="T">byte[] 或其他类型</typeparam>
1807         /// <param name="key">不含prefix前辍</param>
1808         /// <returns></returns>
1809         async public Task<T> RPopAsync<T>(string key) => this.DeserializeRedisValueInternal<T>(await ExecuteScalarAsync(key, (c, k) => c.Value.RPopBytesAsync(k)));
1810         /// <summary>
1811         /// 将列表 source 中的最后一个元素(尾元素)弹出,并返回给客户端。
1812         /// 将 source 弹出的元素插入到列表 destination ,作为 destination 列表的的头元素。
1813         /// </summary>
1814         /// <param name="source">源key,不含prefix前辍</param>
1815         /// <param name="destination">目标key,不含prefix前辍</param>
1816         /// <returns></returns>
1817         public Task<string> RPopLPushAsync(string source, string destination) => NodesNotSupportAsync(new[] { source, destination }, null, (c, k) => c.Value.RPopLPushAsync(k.First(), k.Last()));
1818         /// <summary>
1819         /// 将列表 source 中的最后一个元素(尾元素)弹出,并返回给客户端。
1820         /// 将 source 弹出的元素插入到列表 destination ,作为 destination 列表的的头元素。
1821         /// </summary>
1822         /// <typeparam name="T">byte[] 或其他类型</typeparam>
1823         /// <param name="source">源key,不含prefix前辍</param>
1824         /// <param name="destination">目标key,不含prefix前辍</param>
1825         /// <returns></returns>
1826         async public Task<T> RPopLPushAsync<T>(string source, string destination) => this.DeserializeRedisValueInternal<T>(await NodesNotSupportAsync(new[] { source, destination }, null, (c, k) => c.Value.RPopBytesLPushAsync(k.First(), k.Last())));
1827         /// <summary>
1828         /// 在列表中添加一个或多个值
1829         /// </summary>
1830         /// <param name="key">不含prefix前辍</param>
1831         /// <param name="value">一个或多个值</param>
1832         /// <returns>执行 RPUSH 命令后,列表的长度</returns>
1833         async public Task<long> RPushAsync<T>(string key, params T[] value)
1834         {
1835             if (value == null || value.Any() == false) return 0;
1836             var args = value.Select(z => this.SerializeRedisValueInternal(z)).ToArray();
1837             return await ExecuteScalarAsync(key, (c, k) => c.Value.RPushAsync(k, args));
1838         }
1839         /// <summary>
1840         /// 为已存在的列表添加值
1841         /// </summary>
1842         /// <param name="key">不含prefix前辍</param>
1843         /// <param name="value">一个或多个值</param>
1844         /// <returns>执行 RPUSHX 命令后,列表的长度</returns>
1845         public Task<long> RPushXAsync(string key, object value)
1846         {
1847             var args = this.SerializeRedisValueInternal(value);
1848             return ExecuteScalar(key, (c, k) => c.Value.RPushXAsync(k, args));
1849         }
1850         #endregion
1851 
1852         #region Hash
1853         /// <summary>
1854         /// [redis-server 3.2.0] 返回hash指定field的value的字符串长度,如果hash或者field不存在,返回0.
1855         /// </summary>
1856         /// <param name="key">不含prefix前辍</param>
1857         /// <param name="field">字段</param>
1858         /// <returns></returns>
1859         public Task<long> HStrLenAsync(string key, string field) => ExecuteScalarAsync(key, (c, k) => c.Value.HStrLenAsync(k, field));
1860         /// <summary>
1861         /// 删除一个或多个哈希表字段
1862         /// </summary>
1863         /// <param name="key">不含prefix前辍</param>
1864         /// <param name="fields">字段</param>
1865         /// <returns></returns>
1866         async public Task<long> HDelAsync(string key, params string[] fields) => fields == null || fields.Any() == false ? 0 :
1867             await ExecuteScalarAsync(key, (c, k) => c.Value.HDelAsync(k, fields));
1868         /// <summary>
1869         /// 查看哈希表 key 中,指定的字段是否存在
1870         /// </summary>
1871         /// <param name="key">不含prefix前辍</param>
1872         /// <param name="field">字段</param>
1873         /// <returns></returns>
1874         public Task<bool> HExistsAsync(string key, string field) => ExecuteScalarAsync(key, (c, k) => c.Value.HExistsAsync(k, field));
1875         /// <summary>
1876         /// 获取存储在哈希表中指定字段的值
1877         /// </summary>
1878         /// <param name="key">不含prefix前辍</param>
1879         /// <param name="field">字段</param>
1880         /// <returns></returns>
1881         public Task<string> HGetAsync(string key, string field) => ExecuteScalarAsync(key, (c, k) => c.Value.HGetAsync(k, field));
1882         /// <summary>
1883         /// 获取存储在哈希表中指定字段的值
1884         /// </summary>
1885         /// <typeparam name="T">byte[] 或其他类型</typeparam>
1886         /// <param name="key">不含prefix前辍</param>
1887         /// <param name="field">字段</param>
1888         /// <returns></returns>
1889         async public Task<T> HGetAsync<T>(string key, string field) => this.DeserializeRedisValueInternal<T>(await ExecuteScalarAsync(key, (c, k) => c.Value.HGetBytesAsync(k, field)));
1890         /// <summary>
1891         /// 获取在哈希表中指定 key 的所有字段和值
1892         /// </summary>
1893         /// <param name="key">不含prefix前辍</param>
1894         /// <returns></returns>
1895         public Task<Dictionary<string, string>> HGetAllAsync(string key) => ExecuteScalarAsync(key, (c, k) => c.Value.HGetAllAsync(k));
1896         /// <summary>
1897         /// 获取在哈希表中指定 key 的所有字段和值
1898         /// </summary>
1899         /// <typeparam name="T">byte[] 或其他类型</typeparam>
1900         /// <param name="key">不含prefix前辍</param>
1901         /// <returns></returns>
1902         async public Task<Dictionary<string, T>> HGetAllAsync<T>(string key) => this.DeserializeRedisValueDictionaryInternal<string, T>(await ExecuteScalarAsync(key, (c, k) => c.Value.HGetAllBytesAsync(k)));
1903         /// <summary>
1904         /// 为哈希表 key 中的指定字段的整数值加上增量 increment
1905         /// </summary>
1906         /// <param name="key">不含prefix前辍</param>
1907         /// <param name="field">字段</param>
1908         /// <param name="value">增量值(默认=1)</param>
1909         /// <returns></returns>
1910         public Task<long> HIncrByAsync(string key, string field, long value = 1) => ExecuteScalarAsync(key, (c, k) => c.Value.HIncrByAsync(k, field, value));
1911         /// <summary>
1912         /// 为哈希表 key 中的指定字段的整数值加上增量 increment
1913         /// </summary>
1914         /// <param name="key">不含prefix前辍</param>
1915         /// <param name="field">字段</param>
1916         /// <param name="value">增量值(默认=1)</param>
1917         /// <returns></returns>
1918         public Task<decimal> HIncrByFloatAsync(string key, string field, decimal value) => ExecuteScalarAsync(key, (c, k) => c.Value.HIncrByFloatAsync(k, field, value));
1919         /// <summary>
1920         /// 获取所有哈希表中的字段
1921         /// </summary>
1922         /// <param name="key">不含prefix前辍</param>
1923         /// <returns></returns>
1924         public Task<string[]> HKeysAsync(string key) => ExecuteScalarAsync(key, (c, k) => c.Value.HKeysAsync(k));
1925         /// <summary>
1926         /// 获取哈希表中字段的数量
1927         /// </summary>
1928         /// <param name="key">不含prefix前辍</param>
1929         /// <returns></returns>
1930         public Task<long> HLenAsync(string key) => ExecuteScalarAsync(key, (c, k) => c.Value.HLenAsync(k));
1931         /// <summary>
1932         /// 获取存储在哈希表中多个字段的值
1933         /// </summary>
1934         /// <param name="key">不含prefix前辍</param>
1935         /// <param name="fields">字段</param>
1936         /// <returns></returns>
1937         async public Task<string[]> HMGetAsync(string key, params string[] fields) => fields == null || fields.Any() == false ? new string[0] :
1938             await ExecuteScalarAsync(key, (c, k) => c.Value.HMGetAsync(k, fields));
1939         /// <summary>
1940         /// 获取存储在哈希表中多个字段的值
1941         /// </summary>
1942         /// <typeparam name="T">byte[] 或其他类型</typeparam>
1943         /// <param name="key">不含prefix前辍</param>
1944         /// <param name="fields">一个或多个字段</param>
1945         /// <returns></returns>
1946         async public Task<T[]> HMGetAsync<T>(string key, params string[] fields) => fields == null || fields.Any() == false ? new T[0] :
1947             this.DeserializeRedisValueArrayInternal<T>(await ExecuteScalarAsync(key, (c, k) => c.Value.HMGetBytesAsync(k, fields)));
1948         /// <summary>
1949         /// 同时将多个 field-value (域-值)对设置到哈希表 key 中
1950         /// </summary>
1951         /// <param name="key">不含prefix前辍</param>
1952         /// <param name="keyValues">key1 value1 [key2 value2]</param>
1953         /// <returns></returns>
1954         async public Task<bool> HMSetAsync(string key, params object[] keyValues)
1955         {
1956             if (keyValues == null || keyValues.Any() == false) return false;
1957             if (keyValues.Length % 2 != 0) throw new Exception("keyValues 参数是键值对,不应该出现奇数(数量),请检查使用姿势。");
1958             var parms = new List<object>();
1959             for (var a = 0; a < keyValues.Length; a += 2)
1960             {
1961                 var k = string.Concat(keyValues[a]);
1962                 var v = keyValues[a + 1];
1963                 if (string.IsNullOrEmpty(k)) throw new Exception("keyValues 参数是键值对,并且 key 不可为空");
1964                 parms.Add(k);
1965                 parms.Add(this.SerializeRedisValueInternal(v));
1966             }
1967             return await ExecuteScalarAsync(key, (c, k) => c.Value.HMSetAsync(k, parms.ToArray())) == "OK";
1968         }
1969 
1970         async public Task<bool> HMSetAsync(string key, Dictionary<string,string> keyValues)
1971         {
1972             if (keyValues == null || keyValues.Any() == false) return false;
1973             var parms = new List<object>();
1974             foreach(var item in keyValues)
1975             {
1976                 parms.Add(item.Key);
1977                 parms.Add(this.SerializeRedisValueInternal(item.Value));
1978             }
1979             return await ExecuteScalarAsync(key, (c, k) => c.Value.HMSetAsync(k, parms.ToArray())) == "OK";
1980         }
1981         /// <summary>
1982         /// 将哈希表 key 中的字段 field 的值设为 value
1983         /// </summary>
1984         /// <param name="key">不含prefix前辍</param>
1985         /// <param name="field">字段</param>
1986         /// <param name="value"></param>
1987         /// <returns>如果字段是哈希表中的一个新建字段,并且值设置成功,返回true。如果哈希表中域字段已经存在且旧值已被新值覆盖,返回false。</returns>
1988         public Task<bool> HSetAsync(string key, string field, object value)
1989         {
1990             var args = this.SerializeRedisValueInternal(value);
1991             return ExecuteScalarAsync(key, (c, k) => c.Value.HSetAsync(k, field, args));
1992         }
1993         /// <summary>
1994         /// 只有在字段 field 不存在时,设置哈希表字段的值
1995         /// </summary>
1996         /// <param name="key">不含prefix前辍</param>
1997         /// <param name="field">字段</param>
1998         /// <param name="value">值(string 或 byte[])</param>
1999         /// <returns></returns>
2000         public Task<bool> HSetNxAsync(string key, string field, object value)
2001         {
2002             var args = this.SerializeRedisValueInternal(value);
2003             return ExecuteScalarAsync(key, (c, k) => c.Value.HSetNxAsync(k, field, args));
2004         }
2005         /// <summary>
2006         /// 获取哈希表中所有值
2007         /// </summary>
2008         /// <param name="key">不含prefix前辍</param>
2009         /// <returns></returns>
2010         public Task<string[]> HValsAsync(string key) => ExecuteScalarAsync(key, (c, k) => c.Value.HValsAsync(k));
2011         /// <summary>
2012         /// 获取哈希表中所有值
2013         /// </summary>
2014         /// <typeparam name="T">byte[] 或其他类型</typeparam>
2015         /// <param name="key">不含prefix前辍</param>
2016         /// <returns></returns>
2017         async public Task<T[]> HValsAsync<T>(string key) => this.DeserializeRedisValueArrayInternal<T>(await ExecuteScalarAsync(key, (c, k) => c.Value.HValsBytesAsync(k)));
2018         /// <summary>
2019         /// 迭代哈希表中的键值对
2020         /// </summary>
2021         /// <param name="key">不含prefix前辍</param>
2022         /// <param name="cursor">位置</param>
2023         /// <param name="pattern">模式</param>
2024         /// <param name="count">数量</param>
2025         /// <returns></returns>
2026         async public Task<RedisScan<(string field, string value)>> HScanAsync(string key, long cursor, string pattern = null, long? count = null)
2027         {
2028             var scan = await ExecuteScalarAsync(key, (c, k) => c.Value.HScanAsync(k, cursor, pattern, count));
2029             return new RedisScan<(string, string)>(scan.Cursor, scan.Items.Select(z => (z.Item1, z.Item2)).ToArray());
2030         }
2031         /// <summary>
2032         /// 迭代哈希表中的键值对
2033         /// </summary>
2034         /// <typeparam name="T">byte[] 或其他类型</typeparam>
2035         /// <param name="key">不含prefix前辍</param>
2036         /// <param name="cursor">位置</param>
2037         /// <param name="pattern">模式</param>
2038         /// <param name="count">数量</param>
2039         /// <returns></returns>
2040         async public Task<RedisScan<(string field, T value)>> HScanAsync<T>(string key, long cursor, string pattern = null, long? count = null)
2041         {
2042             var scan = await ExecuteScalarAsync(key, (c, k) => c.Value.HScanBytesAsync(k, cursor, pattern, count));
2043             return new RedisScan<(string, T)>(scan.Cursor, scan.Items.Select(z => (z.Item1, this.DeserializeRedisValueInternal<T>(z.Item2))).ToArray());
2044         }
2045         #endregion
2046 
2047         #region String
2048         /// <summary>
2049         /// 如果 key 已经存在并且是一个字符串, APPEND 命令将指定的 value 追加到该 key 原来值(value)的末尾
2050         /// </summary>
2051         /// <param name="key">不含prefix前辍</param>
2052         /// <param name="value">字符串</param>
2053         /// <returns>追加指定值之后, key 中字符串的长度</returns>
2054         public Task<long> AppendAsync(string key, object value)
2055         {
2056             var args = this.SerializeRedisValueInternal(value);
2057             return ExecuteScalarAsync(key, (c, k) => c.Value.AppendAsync(k, args));
2058         }
2059         /// <summary>
2060         /// 计算给定位置被设置为 1 的比特位的数量
2061         /// </summary>
2062         /// <param name="key">不含prefix前辍</param>
2063         /// <param name="start">开始位置</param>
2064         /// <param name="end">结束位置</param>
2065         /// <returns></returns>
2066         public Task<long> BitCountAsync(string key, long start, long end) => ExecuteScalarAsync(key, (c, k) => c.Value.BitCountAsync(k, start, end));
2067         /// <summary>
2068         /// 对一个或多个保存二进制位的字符串 key 进行位元操作,并将结果保存到 destkey 上
2069         /// </summary>
2070         /// <param name="op">And | Or | XOr | Not</param>
2071         /// <param name="destKey">不含prefix前辍</param>
2072         /// <param name="keys">不含prefix前辍</param>
2073         /// <returns>保存到 destkey 的长度,和输入 key 中最长的长度相等</returns>
2074         async public Task<long> BitOpAsync(RedisBitOp op, string destKey, params string[] keys)
2075         {
2076             if (string.IsNullOrEmpty(destKey)) throw new Exception("destKey 不能为空");
2077             if (keys == null || keys.Length == 0) throw new Exception("keys 不能为空");
2078             return await NodesNotSupportAsync(new[] { destKey }.Concat(keys).ToArray(), 0, (c, k) => c.Value.BitOpAsync(op, k.First(), k.Skip(1).ToArray()));
2079         }
2080         /// <summary>
2081         /// 对 key 所储存的值,查找范围内第一个被设置为1或者0的bit位
2082         /// </summary>
2083         /// <param name="key">不含prefix前辍</param>
2084         /// <param name="bit">查找值</param>
2085         /// <param name="start">开始位置,-1是最后一个,-2是倒数第二个</param>
2086         /// <param name="end">结果位置,-1是最后一个,-2是倒数第二个</param>
2087         /// <returns>返回范围内第一个被设置为1或者0的bit位</returns>
2088         public Task<long> BitPosAsync(string key, bool bit, long? start = null, long? end = null) => ExecuteScalarAsync(key, (c, k) => c.Value.BitPosAsync(k, bit, start, end));
2089         /// <summary>
2090         /// 获取指定 key 的值
2091         /// </summary>
2092         /// <param name="key">不含prefix前辍</param>
2093         /// <returns></returns>
2094         public Task<string> GetAsync(string key) => ExecuteScalarAsync(key, (c, k) => c.Value.GetAsync(k));
2095         /// <summary>
2096         /// 获取指定 key 的值
2097         /// </summary>
2098         /// <typeparam name="T">byte[] 或其他类型</typeparam>
2099         /// <param name="key">不含prefix前辍</param>
2100         /// <returns></returns>
2101         async public Task<T> GetAsync<T>(string key) => this.DeserializeRedisValueInternal<T>(await ExecuteScalarAsync(key, (c, k) => c.Value.GetBytesAsync(k)));
2102         /// <summary>
2103         /// 对 key 所储存的值,获取指定偏移量上的位(bit)
2104         /// </summary>
2105         /// <param name="key">不含prefix前辍</param>
2106         /// <param name="offset">偏移量</param>
2107         /// <returns></returns>
2108         public Task<bool> GetBitAsync(string key, uint offset) => ExecuteScalarAsync(key, (c, k) => c.Value.GetBitAsync(k, offset));
2109         /// <summary>
2110         /// 返回 key 中字符串值的子字符
2111         /// </summary>
2112         /// <param name="key">不含prefix前辍</param>
2113         /// <param name="start">开始位置,0表示第一个元素,-1表示最后一个元素</param>
2114         /// <param name="end">结束位置,0表示第一个元素,-1表示最后一个元素</param>
2115         /// <returns></returns>
2116         public Task<string> GetRangeAsync(string key, long start, long end) => ExecuteScalarAsync(key, (c, k) => c.Value.GetRangeAsync(k, start, end));
2117         /// <summary>
2118         /// 返回 key 中字符串值的子字符
2119         /// </summary>
2120         /// <typeparam name="T">byte[] 或其他类型</typeparam>
2121         /// <param name="key">不含prefix前辍</param>
2122         /// <param name="start">开始位置,0表示第一个元素,-1表示最后一个元素</param>
2123         /// <param name="end">结束位置,0表示第一个元素,-1表示最后一个元素</param>
2124         /// <returns></returns>
2125         async public Task<T> GetRangeAsync<T>(string key, long start, long end) => this.DeserializeRedisValueInternal<T>(await ExecuteScalarAsync(key, (c, k) => c.Value.GetRangeBytesAsync(k, start, end)));
2126         /// <summary>
2127         /// 将给定 key 的值设为 value ,并返回 key 的旧值(old value)
2128         /// </summary>
2129         /// <param name="key">不含prefix前辍</param>
2130         /// <param name="value"></param>
2131         /// <returns></returns>
2132         public Task<string> GetSetAsync(string key, object value)
2133         {
2134             var args = this.SerializeRedisValueInternal(value);
2135             return ExecuteScalarAsync(key, (c, k) => c.Value.GetSetAsync(k, args));
2136         }
2137         /// <summary>
2138         /// 将给定 key 的值设为 value ,并返回 key 的旧值(old value)
2139         /// </summary>
2140         /// <typeparam name="T">byte[] 或其他类型</typeparam>
2141         /// <param name="key">不含prefix前辍</param>
2142         /// <param name="value"></param>
2143         /// <returns></returns>
2144         async public Task<T> GetSetAsync<T>(string key, object value)
2145         {
2146             var args = this.SerializeRedisValueInternal(value);
2147             return this.DeserializeRedisValueInternal<T>(await ExecuteScalarAsync(key, (c, k) => c.Value.GetSetBytesAsync(k, args)));
2148         }
2149         /// <summary>
2150         /// 将 key 所储存的值加上给定的增量值(increment)
2151         /// </summary>
2152         /// <param name="key">不含prefix前辍</param>
2153         /// <param name="value">增量值(默认=1)</param>
2154         /// <returns></returns>
2155         public Task<long> IncrByAsync(string key, long value = 1) => ExecuteScalarAsync(key, (c, k) => c.Value.IncrByAsync(k, value));
2156         /// <summary>
2157         /// 将 key 所储存的值加上给定的浮点增量值(increment)
2158         /// </summary>
2159         /// <param name="key">不含prefix前辍</param>
2160         /// <param name="value">增量值(默认=1)</param>
2161         /// <returns></returns>
2162         public Task<decimal> IncrByFloatAsync(string key, decimal value) => ExecuteScalarAsync(key, (c, k) => c.Value.IncrByFloatAsync(k, value));
2163         /// <summary>
2164         /// 将 key 中储存的数字值减一。
2165         /// </summary>
2166         /// <param name="key">不含prefix前辍</param>
2167         /// <returns></returns>
2168         public long Decr(string key) => ExecuteScalar(key, (c, k) => c.Value.Decr(key));
2169         /// <summary>
2170         /// 将 key 中储存的数字值减一。
2171         /// </summary>
2172         /// <param name="key">不含prefix前辍</param>
2173         /// <returns></returns>
2174         public Task<long> DecrAsync(string key) => ExecuteScalarAsync(key, (c, k) => c.Value.DecrAsync(key));
2175         /// <summary>
2176         /// key 所储存的值减去给定的减量值(decrement) 。
2177         /// </summary>
2178         /// <param name="key">不含prefix前辍</param>
2179         /// <param name="value">增量值(默认=1)</param>
2180         /// <returns></returns>
2181         public long DecrBy(string key, long value = 1) => ExecuteScalar(key, (c, k) => c.Value.DecrBy(k, value));
2182         /// <summary>
2183         /// key 所储存的值减去给定的减量值(decrement) 。
2184         /// </summary>
2185         /// <param name="key">不含prefix前辍</param>
2186         /// <param name="value">增量值(默认=1)</param>
2187         /// <returns></returns>
2188         public Task<long> DecrByAsync(string key, long value = 1) => ExecuteScalarAsync(key, (c, k) => c.Value.DecrByAsync(k, value));
2189         /// <summary>
2190         /// 获取多个指定 key 的值(数组)
2191         /// </summary>
2192         /// <param name="keys">不含prefix前辍</param>
2193         /// <returns></returns>
2194         public Task<string[]> MGetAsync(params string[] keys) => ExecuteArrayAsync(keys, (c, k) => c.Value.MGetAsync(k));
2195         /// <summary>
2196         /// 获取多个指定 key 的值(数组)
2197         /// </summary>
2198         /// <typeparam name="T">byte[] 或其他类型</typeparam>
2199         /// <param name="keys">不含prefix前辍</param>
2200         /// <returns></returns>
2201         async public Task<T[]> MGetAsync<T>(params string[] keys) => this.DeserializeRedisValueArrayInternal<T>(await ExecuteArrayAsync(keys, (c, k) => c.Value.MGetBytesAsync(k)));
2202         /// <summary>
2203         /// 同时设置一个或多个 key-value 对
2204         /// </summary>
2205         /// <param name="keyValues">key1 value1 [key2 value2]</param>
2206         /// <returns></returns>
2207         public Task<bool> MSetAsync(params object[] keyValues) => MSetInternalAsync(RedisExistence.Xx, keyValues);
2208         /// <summary>
2209         /// 同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在
2210         /// </summary>
2211         /// <param name="keyValues">key1 value1 [key2 value2]</param>
2212         /// <returns></returns>
2213         public Task<bool> MSetNxAsync(params object[] keyValues) => MSetInternalAsync(RedisExistence.Nx, keyValues);
2214         async internal Task<bool> MSetInternalAsync(RedisExistence exists, params object[] keyValues)
2215         {
2216             if (keyValues == null || keyValues.Any() == false) return false;
2217             if (keyValues.Length % 2 != 0) throw new Exception("keyValues 参数是键值对,不应该出现奇数(数量),请检查使用姿势。");
2218             var dic = new Dictionary<string, object>();
2219             for (var a = 0; a < keyValues.Length; a += 2)
2220             {
2221                 var k = string.Concat(keyValues[a]);
2222                 var v = this.SerializeRedisValueInternal(keyValues[a + 1]);
2223                 if (string.IsNullOrEmpty(k)) throw new Exception("keyValues 参数是键值对,并且 key 不可为空");
2224                 if (dic.ContainsKey(k)) dic[k] = v;
2225                 else dic.Add(k, v);
2226             }
2227             Func<Object<RedisClient>, string[], Task<long>> handle = async (c, k) =>
2228             {
2229                 var prefix = (c.Pool as RedisClientPool)?.Prefix;
2230                 var parms = new object[k.Length * 2];
2231                 for (var a = 0; a < k.Length; a++)
2232                 {
2233                     parms[a * 2] = k[a];
2234                     parms[a * 2 + 1] = dic[string.IsNullOrEmpty(prefix) ? k[a] : k[a].Substring(prefix.Length)];
2235                 }
2236                 if (exists == RedisExistence.Nx) return await c.Value.MSetNxAsync(parms) ? 1 : 0;
2237                 return await c.Value.MSetAsync(parms) == "OK" ? 1 : 0;
2238             };
2239             if (exists == RedisExistence.Nx) return await NodesNotSupportAsync(dic.Keys.ToArray(), 0, handle) > 0;
2240             return await ExecuteNonQueryAsync(dic.Keys.ToArray(), handle) > 0;
2241         }
2242         /// <summary>
2243         /// 设置指定 key 的值,所有写入参数object都支持string | byte[] | 数值 | 对象
2244         /// </summary>
2245         /// <param name="key">不含prefix前辍</param>
2246         /// <param name="value"></param>
2247         /// <param name="expireSeconds">过期(秒单位)</param>
2248         /// <param name="exists">Nx, Xx</param>
2249         /// <returns></returns>
2250         async public Task<bool> SetAsync(string key, object value, int expireSeconds = -1, RedisExistence? exists = null)
2251         {
2252             object redisValule = this.SerializeRedisValueInternal(value);
2253             if (expireSeconds <= 0 && exists == null) return await ExecuteScalarAsync(key, (c, k) => c.Value.SetAsync(k, redisValule)) == "OK";
2254             if (expireSeconds <= 0 && exists != null) return await ExecuteScalarAsync(key, (c, k) => c.Value.SetAsync(k, redisValule, null, exists)) == "OK";
2255             if (expireSeconds > 0 && exists == null) return await ExecuteScalarAsync(key, (c, k) => c.Value.SetAsync(k, redisValule, expireSeconds, null)) == "OK";
2256             if (expireSeconds > 0 && exists != null) return await ExecuteScalarAsync(key, (c, k) => c.Value.SetAsync(k, redisValule, expireSeconds, exists)) == "OK";
2257             return false;
2258         }
2259         async public Task<bool> SetAsync(string key, object value, TimeSpan expire, RedisExistence? exists = null)
2260         {
2261             object redisValule = this.SerializeRedisValueInternal(value);
2262             if (expire <= TimeSpan.Zero && exists == null) return await ExecuteScalar(key, (c, k) => c.Value.SetAsync(k, redisValule)) == "OK";
2263             if (expire <= TimeSpan.Zero && exists != null) return await ExecuteScalar(key, (c, k) => c.Value.SetAsync(k, redisValule, null, exists)) == "OK";
2264             if (expire > TimeSpan.Zero && exists == null) return await ExecuteScalar(key, (c, k) => c.Value.SetAsync(k, redisValule, expire, null)) == "OK";
2265             if (expire > TimeSpan.Zero && exists != null) return await ExecuteScalar(key, (c, k) => c.Value.SetAsync(k, redisValule, expire, exists)) == "OK";
2266             return false;
2267         }
2268         /// <summary>
2269         /// 对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit)
2270         /// </summary>
2271         /// <param name="key">不含prefix前辍</param>
2272         /// <param name="offset">偏移量</param>
2273         /// <param name="value"></param>
2274         /// <returns></returns>
2275         public Task<bool> SetBitAsync(string key, uint offset, bool value) => ExecuteScalarAsync(key, (c, k) => c.Value.SetBitAsync(k, offset, value));
2276         /// <summary>
2277         /// 只有在 key 不存在时设置 key 的值
2278         /// </summary>
2279         /// <param name="key">不含prefix前辍</param>
2280         /// <param name="value"></param>
2281         /// <returns></returns>
2282         public Task<bool> SetNxAsync(string key, object value)
2283         {
2284             var args = this.SerializeRedisValueInternal(value);
2285             return ExecuteScalarAsync(key, (c, k) => c.Value.SetNxAsync(k, args));
2286         }
2287         /// <summary>
2288         /// 用 value 参数覆写给定 key 所储存的字符串值,从偏移量 offset 开始
2289         /// </summary>
2290         /// <param name="key">不含prefix前辍</param>
2291         /// <param name="offset">偏移量</param>
2292         /// <param name="value"></param>
2293         /// <returns>被修改后的字符串长度</returns>
2294         public Task<long> SetRangeAsync(string key, uint offset, object value)
2295         {
2296             var args = this.SerializeRedisValueInternal(value);
2297             return ExecuteScalarAsync(key, (c, k) => c.Value.SetRangeAsync(k, offset, args));
2298         }
2299         /// <summary>
2300         /// 返回 key 所储存的字符串值的长度
2301         /// </summary>
2302         /// <param name="key">不含prefix前辍</param>
2303         /// <returns></returns>
2304         public Task<long> StrLenAsync(string key) => ExecuteScalarAsync(key, (c, k) => c.Value.StrLenAsync(k));
2305         #endregion
2306 
2307         #region Key
2308         /// <summary>
2309         /// [redis-server 3.2.1] 修改指定key(s) 最后访问时间 若key不存在,不做操作
2310         /// </summary>
2311         /// <param name="key">不含prefix前辍</param>
2312         /// <returns></returns>
2313         public Task<long> TouchAsync(params string[] key) => ExecuteNonQueryAsync(key, (c, k) => c.Value.TouchAsync(k));
2314         /// <summary>
2315         /// [redis-server 4.0.0] Delete a key, 该命令和DEL十分相似:删除指定的key(s),若key不存在则该key被跳过。但是,相比DEL会产生阻塞,该命令会在另一个线程中回收内存,因此它是非阻塞的。 这也是该命令名字的由来:仅将keys从keyspace元数据中删除,真正的删除会在后续异步操作。
2316         /// </summary>
2317         /// <param name="key">不含prefix前辍</param>
2318         /// <returns></returns>
2319         public Task<long> UnLinkAsync(params string[] key) => ExecuteNonQueryAsync(key, (c, k) => c.Value.UnLinkAsync(k));
2320         /// <summary>
2321         /// 用于在 key 存在时删除 key
2322         /// </summary>
2323         /// <param name="key">不含prefix前辍</param>
2324         /// <returns></returns>
2325         public Task<long> DelAsync(params string[] key) => ExecuteNonQueryAsync(key, (c, k) => c.Value.DelAsync(k));
2326         /// <summary>
2327         /// 序列化给定 key ,并返回被序列化的值
2328         /// </summary>
2329         /// <param name="key">不含prefix前辍</param>
2330         /// <returns></returns>
2331         public Task<byte[]> DumpAsync(string key) => ExecuteScalarAsync(key, (c, k) => c.Value.DumpAsync(k));
2332         /// <summary>
2333         /// 检查给定 key 是否存在
2334         /// </summary>
2335         /// <param name="key">不含prefix前辍</param>
2336         /// <returns></returns>
2337         public Task<bool> ExistsAsync(string key) => ExecuteScalarAsync(key, (c, k) => c.Value.ExistsAsync(k));
2338         /// <summary>
2339         /// [redis-server 3.0] 检查给定多个 key 是否存在
2340         /// </summary>
2341         /// <param name="keys">不含prefix前辍</param>
2342         /// <returns></returns>
2343         public Task<long> ExistsAsync(string[] keys) => NodesNotSupportAsync(keys, 0, (c, k) => c.Value.ExistsAsync(k));
2344         /// <summary>
2345         /// 为给定 key 设置过期时间
2346         /// </summary>
2347         /// <param name="key">不含prefix前辍</param>
2348         /// <param name="seconds">过期秒数</param>
2349         /// <returns></returns>
2350         public Task<bool> ExpireAsync(string key, int seconds) => ExecuteScalarAsync(key, (c, k) => c.Value.ExpireAsync(k, seconds));
2351         /// <summary>
2352         /// 为给定 key 设置过期时间
2353         /// </summary>
2354         /// <param name="key">不含prefix前辍</param>
2355         /// <param name="expire">过期时间</param>
2356         /// <returns></returns>
2357         public Task<bool> ExpireAsync(string key, TimeSpan expire) => ExecuteScalarAsync(key, (c, k) => c.Value.ExpireAsync(k, expire));
2358         /// <summary>
2359         /// 为给定 key 设置过期时间
2360         /// </summary>
2361         /// <param name="key">不含prefix前辍</param>
2362         /// <param name="expire">过期时间</param>
2363         /// <returns></returns>
2364         public Task<bool> ExpireAtAsync(string key, DateTime expire) => ExecuteScalarAsync(key, (c, k) => c.Value.ExpireAtAsync(k, expire));
2365         /// <summary>
2366         /// 查找所有分区节点中符合给定模式(pattern)的 key
2367         /// </summary>
2368         /// <param name="pattern">如:runoob*</param>
2369         /// <returns></returns>
2370         async public Task<string[]> KeysAsync(string pattern)
2371         {
2372             List<string> ret = new List<string>();
2373             foreach (var pool in Nodes)
2374                 ret.AddRange(await GetAndExecuteAsync(pool.Value, conn => conn.Value.KeysAsync(pattern)));
2375             return ret.ToArray();
2376         }
2377         /// <summary>
2378         /// 将当前数据库的 key 移动到给定的数据库 db 当中
2379         /// </summary>
2380         /// <param name="key">不含prefix前辍</param>
2381         /// <param name="database">数据库</param>
2382         /// <returns></returns>
2383         public Task<bool> MoveAsync(string key, int database) => ExecuteScalarAsync(key, (c, k) => c.Value.MoveAsync(k, database));
2384         /// <summary>
2385         /// 该返回给定 key 锁储存的值所使用的内部表示(representation)
2386         /// </summary>
2387         /// <param name="key">不含prefix前辍</param>
2388         /// <returns></returns>
2389         public Task<string> ObjectEncodingAsync(string key) => ExecuteScalarAsync(key, (c, k) => c.Value.ObjectEncodingAsync(k));
2390         /// <summary>
2391         /// 该返回给定 key 引用所储存的值的次数。此命令主要用于除错
2392         /// </summary>
2393         /// <param name="key">不含prefix前辍</param>
2394         /// <returns></returns>
2395         public Task<long?> ObjectRefCountAsync(string key) => ExecuteScalarAsync(key, (c, k) => c.Value.ObjectAsync(RedisObjectSubCommand.RefCount, k));
2396         /// <summary>
2397         /// 返回给定 key 自储存以来的空转时间(idle, 没有被读取也没有被写入),以秒为单位
2398         /// </summary>
2399         /// <param name="key">不含prefix前辍</param>
2400         /// <returns></returns>
2401         public Task<long?> ObjectIdleTimeAsync(string key) => ExecuteScalarAsync(key, (c, k) => c.Value.ObjectAsync(RedisObjectSubCommand.IdleTime, k));
2402         /// <summary>
2403         /// 移除 key 的过期时间,key 将持久保持
2404         /// </summary>
2405         /// <param name="key">不含prefix前辍</param>
2406         /// <returns></returns>
2407         public Task<bool> PersistAsync(string key) => ExecuteScalarAsync(key, (c, k) => c.Value.PersistAsync(k));
2408         /// <summary>
2409         /// 为给定 key 设置过期时间(毫秒)
2410         /// </summary>
2411         /// <param name="key">不含prefix前辍</param>
2412         /// <param name="milliseconds">过期毫秒数</param>
2413         /// <returns></returns>
2414         public Task<bool> PExpireAsync(string key, int milliseconds) => ExecuteScalarAsync(key, (c, k) => c.Value.PExpireAsync(k, milliseconds));
2415         /// <summary>
2416         /// 为给定 key 设置过期时间(毫秒)
2417         /// </summary>
2418         /// <param name="key">不含prefix前辍</param>
2419         /// <param name="expire">过期时间</param>
2420         /// <returns></returns>
2421         public Task<bool> PExpireAsync(string key, TimeSpan expire) => ExecuteScalarAsync(key, (c, k) => c.Value.PExpireAsync(k, expire));
2422         /// <summary>
2423         /// 为给定 key 设置过期时间(毫秒)
2424         /// </summary>
2425         /// <param name="key">不含prefix前辍</param>
2426         /// <param name="expire">过期时间</param>
2427         /// <returns></returns>
2428         public Task<bool> PExpireAtAsync(string key, DateTime expire) => ExecuteScalarAsync(key, (c, k) => c.Value.PExpireAtAsync(k, expire));
2429         /// <summary>
2430         /// 以毫秒为单位返回 key 的剩余的过期时间
2431         /// </summary>
2432         /// <param name="key">不含prefix前辍</param>
2433         /// <returns></returns>
2434         public Task<long> PTtlAsync(string key) => ExecuteScalarAsync(key, (c, k) => c.Value.PTtlAsync(k));
2435         /// <summary>
2436         /// 从所有节点中随机返回一个 key
2437         /// </summary>
2438         /// <returns>返回的 key 如果包含 prefix前辍,则会去除后返回</returns>
2439         public Task<string> RandomKeyAsync() => GetAndExecuteAsync(Nodes[NodesIndex[_rnd.Next(0, NodesIndex.Count)]], async c =>
2440         {
2441             var rk = await c.Value.RandomKeyAsync();
2442             var prefix = (c.Pool as RedisClientPool).Prefix;
2443             if (string.IsNullOrEmpty(prefix) == false && rk.StartsWith(prefix)) return rk.Substring(prefix.Length);
2444             return rk;
2445         });
2446         /// <summary>
2447         /// 修改 key 的名称
2448         /// </summary>
2449         /// <param name="key">旧名称,不含prefix前辍</param>
2450         /// <param name="newKey">新名称,不含prefix前辍</param>
2451         /// <returns></returns>
2452         async public Task<bool> RenameAsync(string key, string newKey)
2453         {
2454             string rule = string.Empty;
2455             if (Nodes.Count > 1)
2456             {
2457                 var rule1 = NodeRuleRaw(key);
2458                 var rule2 = NodeRuleRaw(newKey);
2459                 if (rule1 != rule2)
2460                 {
2461                     var ret = StartPipe(a => a.Dump(key).Del(key));
2462                     int.TryParse(ret[1]?.ToString(), out var tryint);
2463                     if (ret[0] == null || tryint <= 0) return false;
2464                     return await RestoreAsync(newKey, (byte[])ret[0]);
2465                 }
2466                 rule = rule1;
2467             }
2468             var pool = Nodes.TryGetValue(rule, out var b) ? b : Nodes.First().Value;
2469             var key1 = string.Concat(pool.Prefix, key);
2470             var key2 = string.Concat(pool.Prefix, newKey);
2471             return await GetAndExecuteAsync(pool, conn => conn.Value.RenameAsync(key1, key2)) == "OK";
2472         }
2473         /// <summary>
2474         /// 修改 key 的名称
2475         /// </summary>
2476         /// <param name="key">旧名称,不含prefix前辍</param>
2477         /// <param name="newKey">新名称,不含prefix前辍</param>
2478         /// <returns></returns>
2479         public Task<bool> RenameNxAsync(string key, string newKey) => NodesNotSupportAsync(new[] { key, newKey }, false, (c, k) => c.Value.RenameNxAsync(k.First(), k.Last()));
2480         /// <summary>
2481         /// 反序列化给定的序列化值,并将它和给定的 key 关联
2482         /// </summary>
2483         /// <param name="key">不含prefix前辍</param>
2484         /// <param name="serializedValue">序列化值</param>
2485         /// <returns></returns>
2486         public Task<bool> RestoreAsync(string key, byte[] serializedValue) => ExecuteScalarAsync(key, async (c, k) => await c.Value.RestoreAsync(k, 0, serializedValue) == "OK");
2487         /// <summary>
2488         /// 反序列化给定的序列化值,并将它和给定的 key 关联
2489         /// </summary>
2490         /// <param name="key">不含prefix前辍</param>
2491         /// <param name="ttlMilliseconds">毫秒为单位为 key 设置生存时间</param>
2492         /// <param name="serializedValue">序列化值</param>
2493         /// <returns></returns>
2494         public Task<bool> RestoreAsync(string key, long ttlMilliseconds, byte[] serializedValue) => ExecuteScalarAsync(key, async (c, k) => await c.Value.RestoreAsync(k, ttlMilliseconds, serializedValue) == "OK");
2495         /// <summary>
2496         /// 返回给定列表、集合、有序集合 key 中经过排序的元素,参数资料:http://doc.redisfans.com/key/sort.html
2497         /// </summary>
2498         /// <param name="key">列表、集合、有序集合,不含prefix前辍</param>
2499         /// <param name="offset">偏移量</param>
2500         /// <param name="count">数量</param>
2501         /// <param name="by">排序字段</param>
2502         /// <param name="dir">排序方式</param>
2503         /// <param name="isAlpha">对字符串或数字进行排序</param>
2504         /// <param name="get">根据排序的结果来取出相应的键值</param>
2505         /// <returns></returns>
2506         public Task<string[]> SortAsync(string key, long? count = null, long offset = 0, string by = null, RedisSortDir? dir = null, bool? isAlpha = null, params string[] get) =>
2507             NodesNotSupportAsync(key, (c, k) => c.Value.SortAsync(k, offset, count, by, dir, isAlpha, get));
2508         /// <summary>
2509         /// 保存给定列表、集合、有序集合 key 中经过排序的元素,参数资料:http://doc.redisfans.com/key/sort.html
2510         /// </summary>
2511         /// <param name="key">列表、集合、有序集合,不含prefix前辍</param>
2512         /// <param name="destination">目标key,不含prefix前辍</param>
2513         /// <param name="offset">偏移量</param>
2514         /// <param name="count">数量</param>
2515         /// <param name="by">排序字段</param>
2516         /// <param name="dir">排序方式</param>
2517         /// <param name="isAlpha">对字符串或数字进行排序</param>
2518         /// <param name="get">根据排序的结果来取出相应的键值</param>
2519         /// <returns></returns>
2520         public Task<long> SortAndStoreAsync(string key, string destination, long? count = null, long offset = 0, string by = null, RedisSortDir? dir = null, bool? isAlpha = null, params string[] get) =>
2521             NodesNotSupportAsync(key, (c, k) => c.Value.SortAndStoreAsync(k, (c.Pool as RedisClientPool)?.Prefix + destination, offset, count, by, dir, isAlpha, get));
2522         /// <summary>
2523         /// 以秒为单位,返回给定 key 的剩余生存时间
2524         /// </summary>
2525         /// <param name="key">不含prefix前辍</param>
2526         /// <returns></returns>
2527         public Task<long> TtlAsync(string key) => ExecuteScalarAsync(key, (c, k) => c.Value.TtlAsync(k));
2528         /// <summary>
2529         /// 返回 key 所储存的值的类型
2530         /// </summary>
2531         /// <param name="key">不含prefix前辍</param>
2532         /// <returns></returns>
2533         async public Task<KeyType> TypeAsync(string key) => Enum.TryParse(await ExecuteScalarAsync(key, (c, k) => c.Value.TypeAsync(k)), true, out KeyType tryenum) ? tryenum : KeyType.None;
2534         /// <summary>
2535         /// 迭代当前数据库中的数据库键
2536         /// </summary>
2537         /// <param name="cursor">位置</param>
2538         /// <param name="pattern">模式</param>
2539         /// <param name="count">数量</param>
2540         /// <returns></returns>
2541         public Task<RedisScan<string>> ScanAsync(long cursor, string pattern = null, long? count = null) => NodesNotSupportAsync("ScanAsync", (c, k) => c.Value.ScanAsync(cursor, pattern, count));
2542         /// <summary>
2543         /// 迭代当前数据库中的数据库键
2544         /// </summary>
2545         /// <typeparam name="T">byte[] 或其他类型</typeparam>
2546         /// <param name="cursor">位置</param>
2547         /// <param name="pattern">模式</param>
2548         /// <param name="count">数量</param>
2549         /// <returns></returns>
2550         async public Task<RedisScan<T>> ScanAsync<T>(long cursor, string pattern = null, long? count = null)
2551         {
2552             var scan = await NodesNotSupportAsync("ScanAsync<T>", (c, k) => c.Value.ScanBytesAsync(cursor, pattern, count));
2553             return new RedisScan<T>(scan.Cursor, this.DeserializeRedisValueArrayInternal<T>(scan.Items));
2554         }
2555         #endregion
2556 
2557         #region Geo redis-server 3.2
2558         /// <summary>
2559         /// 将指定的地理空间位置(纬度、经度、成员)添加到指定的key中。这些数据将会存储到sorted set这样的目的是为了方便使用GEORADIUS或者GEORADIUSBYMEMBER命令对数据进行半径查询等操作。
2560         /// </summary>
2561         /// <param name="key">不含prefix前辍</param>
2562         /// <param name="longitude">经度</param>
2563         /// <param name="latitude">纬度</param>
2564         /// <param name="member">成员</param>
2565         /// <returns>是否成功</returns>
2566         async public Task<bool> GeoAddAsync(string key, decimal longitude, decimal latitude, object member) => await GeoAddAsync(key, (longitude, latitude, member)) == 1;
2567         /// <summary>
2568         /// 将指定的地理空间位置(纬度、经度、成员)添加到指定的key中。这些数据将会存储到sorted set这样的目的是为了方便使用GEORADIUS或者GEORADIUSBYMEMBER命令对数据进行半径查询等操作。
2569         /// </summary>
2570         /// <param name="key">不含prefix前辍</param>
2571         /// <param name="values">批量添加的值</param>
2572         /// <returns>添加到sorted set元素的数目,但不包括已更新score的元素。</returns>
2573         async public Task<long> GeoAddAsync(string key, params (decimal longitude, decimal latitude, object member)[] values)
2574         {
2575             if (values == null || values.Any() == false) return 0;
2576             var args = values.Select(z => (z.longitude, z.latitude, this.SerializeRedisValueInternal(z.member))).ToArray();
2577             return await ExecuteScalarAsync(key, (c, k) => c.Value.GeoAddAsync(k, args));
2578         }
2579         /// <summary>
2580         /// 返回两个给定位置之间的距离。如果两个位置之间的其中一个不存在, 那么命令返回空值。GEODIST 命令在计算距离时会假设地球为完美的球形, 在极限情况下, 这一假设最大会造成 0.5% 的误差。
2581         /// </summary>
2582         /// <param name="key">不含prefix前辍</param>
2583         /// <param name="member1">成员1</param>
2584         /// <param name="member2">成员2</param>
2585         /// <param name="unit">m 表示单位为米;km 表示单位为千米;mi 表示单位为英里;ft 表示单位为英尺;</param>
2586         /// <returns>计算出的距离会以双精度浮点数的形式被返回。 如果给定的位置元素不存在, 那么命令返回空值。</returns>
2587         public Task<decimal?> GeoDistAsync(string key, object member1, object member2, GeoUnit unit = GeoUnit.m)
2588         {
2589             var args1 = this.SerializeRedisValueInternal(member1);
2590             var args2 = this.SerializeRedisValueInternal(member2);
2591             return ExecuteScalarAsync(key, (c, k) => c.Value.GeoDistAsync(k, args1, args2, unit));
2592         }
2593         /// <summary>
2594         /// 返回一个或多个位置元素的 Geohash 表示。通常使用表示位置的元素使用不同的技术,使用Geohash位置52点整数编码。由于编码和解码过程中所使用的初始最小和最大坐标不同,编码的编码也不同于标准。
2595         /// </summary>
2596         /// <param name="key">不含prefix前辍</param>
2597         /// <param name="members">多个查询的成员</param>
2598         /// <returns>一个数组, 数组的每个项都是一个 geohash 。 命令返回的 geohash 的位置与用户给定的位置元素的位置一一对应。</returns>
2599         async public Task<string[]> GeoHashAsync(string key, object[] members)
2600         {
2601             if (members == null || members.Any() == false) return new string[0];
2602             var args = members.Select(z => this.SerializeRedisValueInternal(z)).ToArray();
2603             return await ExecuteScalarAsync(key, (c, k) => c.Value.GeoHashAsync(k, args));
2604         }
2605         /// <summary>
2606         /// 从key里返回所有给定位置元素的位置(经度和纬度)。
2607         /// </summary>
2608         /// <param name="key">不含prefix前辍</param>
2609         /// <param name="members">多个查询的成员</param>
2610         /// <returns>GEOPOS 命令返回一个数组, 数组中的每个项都由两个元素组成: 第一个元素为给定位置元素的经度, 而第二个元素则为给定位置元素的纬度。当给定的位置元素不存在时, 对应的数组项为空值。</returns>
2611         async public Task<(decimal longitude, decimal latitude)?[]> GeoPosAsync(string key, object[] members)
2612         {
2613             if (members == null || members.Any() == false) return new (decimal, decimal)?[0];
2614             var args = members.Select(z => this.SerializeRedisValueInternal(z)).ToArray();
2615             return await ExecuteScalarAsync(key, (c, k) => c.Value.GeoPosAsync(k, args));
2616         }
2617 
2618         /// <summary>
2619         /// 以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素。
2620         /// </summary>
2621         /// <param name="key">不含prefix前辍</param>
2622         /// <param name="longitude">经度</param>
2623         /// <param name="latitude">纬度</param>
2624         /// <param name="radius">距离</param>
2625         /// <param name="unit">m 表示单位为米;km 表示单位为千米;mi 表示单位为英里;ft 表示单位为英尺;</param>
2626         /// <param name="count">虽然用户可以使用 COUNT 选项去获取前 N 个匹配元素, 但是因为命令在内部可能会需要对所有被匹配的元素进行处理, 所以在对一个非常大的区域进行搜索时, 即使只使用 COUNT 选项去获取少量元素, 命令的执行速度也可能会非常慢。 但是从另一方面来说, 使用 COUNT 选项去减少需要返回的元素数量, 对于减少带宽来说仍然是非常有用的。</param>
2627         /// <param name="sorting">排序</param>
2628         /// <returns></returns>
2629         async public Task<string[]> GeoRadiusAsync(string key, decimal longitude, decimal latitude, decimal radius, GeoUnit unit = GeoUnit.m, long? count = null, GeoOrderBy? sorting = null) =>
2630             (await ExecuteScalarAsync(key, (c, k) => c.Value.GeoRadiusAsync(k, longitude, latitude, radius, unit, count, sorting, false, false, false))).Select(a => a.member).ToArray();
2631         /// <summary>
2632         /// 以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素。
2633         /// </summary>
2634         /// <param name="key">不含prefix前辍</param>
2635         /// <param name="longitude">经度</param>
2636         /// <param name="latitude">纬度</param>
2637         /// <param name="radius">距离</param>
2638         /// <param name="unit">m 表示单位为米;km 表示单位为千米;mi 表示单位为英里;ft 表示单位为英尺;</param>
2639         /// <param name="count">虽然用户可以使用 COUNT 选项去获取前 N 个匹配元素, 但是因为命令在内部可能会需要对所有被匹配的元素进行处理, 所以在对一个非常大的区域进行搜索时, 即使只使用 COUNT 选项去获取少量元素, 命令的执行速度也可能会非常慢。 但是从另一方面来说, 使用 COUNT 选项去减少需要返回的元素数量, 对于减少带宽来说仍然是非常有用的。</param>
2640         /// <param name="sorting">排序</param>
2641         /// <returns></returns>
2642         async public Task<T[]> GeoRadiusAsync<T>(string key, decimal longitude, decimal latitude, decimal radius, GeoUnit unit = GeoUnit.m, long? count = null, GeoOrderBy? sorting = null) =>
2643             (await ExecuteScalarAsync(key, (c, k) => c.Value.GeoRadiusBytesAsync(k, longitude, latitude, radius, unit, count, sorting, false, false, false))).Select(a => this.DeserializeRedisValueInternal<T>(a.member)).ToArray();
2644 
2645         /// <summary>
2646         /// 以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素(包含距离)。
2647         /// </summary>
2648         /// <param name="key">不含prefix前辍</param>
2649         /// <param name="longitude">经度</param>
2650         /// <param name="latitude">纬度</param>
2651         /// <param name="radius">距离</param>
2652         /// <param name="unit">m 表示单位为米;km 表示单位为千米;mi 表示单位为英里;ft 表示单位为英尺;</param>
2653         /// <param name="count">虽然用户可以使用 COUNT 选项去获取前 N 个匹配元素, 但是因为命令在内部可能会需要对所有被匹配的元素进行处理, 所以在对一个非常大的区域进行搜索时, 即使只使用 COUNT 选项去获取少量元素, 命令的执行速度也可能会非常慢。 但是从另一方面来说, 使用 COUNT 选项去减少需要返回的元素数量, 对于减少带宽来说仍然是非常有用的。</param>
2654         /// <param name="sorting">排序</param>
2655         /// <returns></returns>
2656         async public Task<(string member, decimal dist)[]> GeoRadiusWithDistAsync(string key, decimal longitude, decimal latitude, decimal radius, GeoUnit unit = GeoUnit.m, long? count = null, GeoOrderBy? sorting = null) =>
2657             (await ExecuteScalarAsync(key, (c, k) => c.Value.GeoRadiusAsync(k, longitude, latitude, radius, unit, count, sorting, false, true, false))).Select(a => (a.member, a.dist)).ToArray();
2658         /// <summary>
2659         /// 以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素(包含距离)。
2660         /// </summary>
2661         /// <param name="key">不含prefix前辍</param>
2662         /// <param name="longitude">经度</param>
2663         /// <param name="latitude">纬度</param>
2664         /// <param name="radius">距离</param>
2665         /// <param name="unit">m 表示单位为米;km 表示单位为千米;mi 表示单位为英里;ft 表示单位为英尺;</param>
2666         /// <param name="count">虽然用户可以使用 COUNT 选项去获取前 N 个匹配元素, 但是因为命令在内部可能会需要对所有被匹配的元素进行处理, 所以在对一个非常大的区域进行搜索时, 即使只使用 COUNT 选项去获取少量元素, 命令的执行速度也可能会非常慢。 但是从另一方面来说, 使用 COUNT 选项去减少需要返回的元素数量, 对于减少带宽来说仍然是非常有用的。</param>
2667         /// <param name="sorting">排序</param>
2668         /// <returns></returns>
2669         async public Task<(T member, decimal dist)[]> GeoRadiusWithDistAsync<T>(string key, decimal longitude, decimal latitude, decimal radius, GeoUnit unit = GeoUnit.m, long? count = null, GeoOrderBy? sorting = null) =>
2670             (await ExecuteScalarAsync(key, (c, k) => c.Value.GeoRadiusBytesAsync(k, longitude, latitude, radius, unit, count, sorting, false, true, false))).Select(a => (this.DeserializeRedisValueInternal<T>(a.member), a.dist)).ToArray();
2671 
2672         /// <summary>
2673         /// 以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素(包含经度、纬度)。
2674         /// </summary>
2675         /// <param name="key">不含prefix前辍</param>
2676         /// <param name="longitude">经度</param>
2677         /// <param name="latitude">纬度</param>
2678         /// <param name="radius">距离</param>
2679         /// <param name="unit">m 表示单位为米;km 表示单位为千米;mi 表示单位为英里;ft 表示单位为英尺;</param>
2680         /// <param name="count">虽然用户可以使用 COUNT 选项去获取前 N 个匹配元素, 但是因为命令在内部可能会需要对所有被匹配的元素进行处理, 所以在对一个非常大的区域进行搜索时, 即使只使用 COUNT 选项去获取少量元素, 命令的执行速度也可能会非常慢。 但是从另一方面来说, 使用 COUNT 选项去减少需要返回的元素数量, 对于减少带宽来说仍然是非常有用的。</param>
2681         /// <param name="sorting">排序</param>
2682         /// <returns></returns>
2683         async private Task<(string member, decimal longitude, decimal latitude)[]> GeoRadiusWithCoordAsync(string key, decimal longitude, decimal latitude, decimal radius, GeoUnit unit = GeoUnit.m, long? count = null, GeoOrderBy? sorting = null) =>
2684             (await ExecuteScalarAsync(key, (c, k) => c.Value.GeoRadiusAsync(k, longitude, latitude, radius, unit, count, sorting, true, false, false))).Select(a => (a.member, a.longitude, a.latitude)).ToArray();
2685         /// <summary>
2686         /// 以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素(包含经度、纬度)。
2687         /// </summary>
2688         /// <param name="key">不含prefix前辍</param>
2689         /// <param name="longitude">经度</param>
2690         /// <param name="latitude">纬度</param>
2691         /// <param name="radius">距离</param>
2692         /// <param name="unit">m 表示单位为米;km 表示单位为千米;mi 表示单位为英里;ft 表示单位为英尺;</param>
2693         /// <param name="count">虽然用户可以使用 COUNT 选项去获取前 N 个匹配元素, 但是因为命令在内部可能会需要对所有被匹配的元素进行处理, 所以在对一个非常大的区域进行搜索时, 即使只使用 COUNT 选项去获取少量元素, 命令的执行速度也可能会非常慢。 但是从另一方面来说, 使用 COUNT 选项去减少需要返回的元素数量, 对于减少带宽来说仍然是非常有用的。</param>
2694         /// <param name="sorting">排序</param>
2695         /// <returns></returns>
2696         async private Task<(T member, decimal longitude, decimal latitude)[]> GeoRadiusWithCoordAsync<T>(string key, decimal longitude, decimal latitude, decimal radius, GeoUnit unit = GeoUnit.m, long? count = null, GeoOrderBy? sorting = null) =>
2697             (await ExecuteScalarAsync(key, (c, k) => c.Value.GeoRadiusBytesAsync(k, longitude, latitude, radius, unit, count, sorting, true, false, false))).Select(a => (this.DeserializeRedisValueInternal<T>(a.member), a.longitude, a.latitude)).ToArray();
2698 
2699         /// <summary>
2700         /// 以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素(包含距离、经度、纬度)。
2701         /// </summary>
2702         /// <param name="key">不含prefix前辍</param>
2703         /// <param name="longitude">经度</param>
2704         /// <param name="latitude">纬度</param>
2705         /// <param name="radius">距离</param>
2706         /// <param name="unit">m 表示单位为米;km 表示单位为千米;mi 表示单位为英里;ft 表示单位为英尺;</param>
2707         /// <param name="count">虽然用户可以使用 COUNT 选项去获取前 N 个匹配元素, 但是因为命令在内部可能会需要对所有被匹配的元素进行处理, 所以在对一个非常大的区域进行搜索时, 即使只使用 COUNT 选项去获取少量元素, 命令的执行速度也可能会非常慢。 但是从另一方面来说, 使用 COUNT 选项去减少需要返回的元素数量, 对于减少带宽来说仍然是非常有用的。</param>
2708         /// <param name="sorting">排序</param>
2709         /// <returns></returns>
2710         async public Task<(string member, decimal dist, decimal longitude, decimal latitude)[]> GeoRadiusWithDistAndCoordAsync(string key, decimal longitude, decimal latitude, decimal radius, GeoUnit unit = GeoUnit.m, long? count = null, GeoOrderBy? sorting = null) =>
2711             (await ExecuteScalarAsync(key, (c, k) => c.Value.GeoRadiusAsync(k, longitude, latitude, radius, unit, count, sorting, true, true, false))).Select(a => (a.member, a.dist, a.longitude, a.latitude)).ToArray();
2712         /// <summary>
2713         /// 以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素(包含距离、经度、纬度)。
2714         /// </summary>
2715         /// <param name="key">不含prefix前辍</param>
2716         /// <param name="longitude">经度</param>
2717         /// <param name="latitude">纬度</param>
2718         /// <param name="radius">距离</param>
2719         /// <param name="unit">m 表示单位为米;km 表示单位为千米;mi 表示单位为英里;ft 表示单位为英尺;</param>
2720         /// <param name="count">虽然用户可以使用 COUNT 选项去获取前 N 个匹配元素, 但是因为命令在内部可能会需要对所有被匹配的元素进行处理, 所以在对一个非常大的区域进行搜索时, 即使只使用 COUNT 选项去获取少量元素, 命令的执行速度也可能会非常慢。 但是从另一方面来说, 使用 COUNT 选项去减少需要返回的元素数量, 对于减少带宽来说仍然是非常有用的。</param>
2721         /// <param name="sorting">排序</param>
2722         /// <returns></returns>
2723         async public Task<(T member, decimal dist, decimal longitude, decimal latitude)[]> GeoRadiusWithDistAndCoordAsync<T>(string key, decimal longitude, decimal latitude, decimal radius, GeoUnit unit = GeoUnit.m, long? count = null, GeoOrderBy? sorting = null) =>
2724             (await ExecuteScalarAsync(key, (c, k) => c.Value.GeoRadiusBytesAsync(k, longitude, latitude, radius, unit, count, sorting, true, true, false))).Select(a => (this.DeserializeRedisValueInternal<T>(a.member), a.dist, a.longitude, a.latitude)).ToArray();
2725 
2726         /// <summary>
2727         /// 以给定的成员为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素。
2728         /// </summary>
2729         /// <param name="key">不含prefix前辍</param>
2730         /// <param name="member">成员</param>
2731         /// <param name="radius">距离</param>
2732         /// <param name="unit">m 表示单位为米;km 表示单位为千米;mi 表示单位为英里;ft 表示单位为英尺;</param>
2733         /// <param name="count">虽然用户可以使用 COUNT 选项去获取前 N 个匹配元素, 但是因为命令在内部可能会需要对所有被匹配的元素进行处理, 所以在对一个非常大的区域进行搜索时, 即使只使用 COUNT 选项去获取少量元素, 命令的执行速度也可能会非常慢。 但是从另一方面来说, 使用 COUNT 选项去减少需要返回的元素数量, 对于减少带宽来说仍然是非常有用的。</param>
2734         /// <param name="sorting">排序</param>
2735         /// <returns></returns>
2736         async public Task<string[]> GeoRadiusByMemberAsync(string key, object member, decimal radius, GeoUnit unit = GeoUnit.m, long? count = null, GeoOrderBy? sorting = null) =>
2737             (await ExecuteScalarAsync(key, (c, k) => c.Value.GeoRadiusByMemberAsync(k, member, radius, unit, count, sorting, false, false, false))).Select(a => a.member).ToArray();
2738         /// <summary>
2739         /// 以给定的成员为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素。
2740         /// </summary>
2741         /// <param name="key">不含prefix前辍</param>
2742         /// <param name="member">成员</param>
2743         /// <param name="radius">距离</param>
2744         /// <param name="unit">m 表示单位为米;km 表示单位为千米;mi 表示单位为英里;ft 表示单位为英尺;</param>
2745         /// <param name="count">虽然用户可以使用 COUNT 选项去获取前 N 个匹配元素, 但是因为命令在内部可能会需要对所有被匹配的元素进行处理, 所以在对一个非常大的区域进行搜索时, 即使只使用 COUNT 选项去获取少量元素, 命令的执行速度也可能会非常慢。 但是从另一方面来说, 使用 COUNT 选项去减少需要返回的元素数量, 对于减少带宽来说仍然是非常有用的。</param>
2746         /// <param name="sorting">排序</param>
2747         /// <returns></returns>
2748         async public Task<T[]> GeoRadiusByMemberAsync<T>(string key, object member, decimal radius, GeoUnit unit = GeoUnit.m, long? count = null, GeoOrderBy? sorting = null) =>
2749             (await ExecuteScalarAsync(key, (c, k) => c.Value.GeoRadiusBytesByMemberAsync(k, member, radius, unit, count, sorting, false, false, false))).Select(a => this.DeserializeRedisValueInternal<T>(a.member)).ToArray();
2750 
2751         /// <summary>
2752         /// 以给定的成员为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素(包含距离)。
2753         /// </summary>
2754         /// <param name="key">不含prefix前辍</param>
2755         /// <param name="member">成员</param>
2756         /// <param name="radius">距离</param>
2757         /// <param name="unit">m 表示单位为米;km 表示单位为千米;mi 表示单位为英里;ft 表示单位为英尺;</param>
2758         /// <param name="count">虽然用户可以使用 COUNT 选项去获取前 N 个匹配元素, 但是因为命令在内部可能会需要对所有被匹配的元素进行处理, 所以在对一个非常大的区域进行搜索时, 即使只使用 COUNT 选项去获取少量元素, 命令的执行速度也可能会非常慢。 但是从另一方面来说, 使用 COUNT 选项去减少需要返回的元素数量, 对于减少带宽来说仍然是非常有用的。</param>
2759         /// <param name="sorting">排序</param>
2760         /// <returns></returns>
2761         async public Task<(string member, decimal dist)[]> GeoRadiusByMemberWithDistAsync(string key, object member, decimal radius, GeoUnit unit = GeoUnit.m, long? count = null, GeoOrderBy? sorting = null) =>
2762             (await ExecuteScalarAsync(key, (c, k) => c.Value.GeoRadiusByMemberAsync(k, member, radius, unit, count, sorting, false, true, false))).Select(a => (a.member, a.dist)).ToArray();
2763         /// <summary>
2764         /// 以给定的成员为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素(包含距离)。
2765         /// </summary>
2766         /// <param name="key">不含prefix前辍</param>
2767         /// <param name="member">成员</param>
2768         /// <param name="radius">距离</param>
2769         /// <param name="unit">m 表示单位为米;km 表示单位为千米;mi 表示单位为英里;ft 表示单位为英尺;</param>
2770         /// <param name="count">虽然用户可以使用 COUNT 选项去获取前 N 个匹配元素, 但是因为命令在内部可能会需要对所有被匹配的元素进行处理, 所以在对一个非常大的区域进行搜索时, 即使只使用 COUNT 选项去获取少量元素, 命令的执行速度也可能会非常慢。 但是从另一方面来说, 使用 COUNT 选项去减少需要返回的元素数量, 对于减少带宽来说仍然是非常有用的。</param>
2771         /// <param name="sorting">排序</param>
2772         /// <returns></returns>
2773         async public Task<(T member, decimal dist)[]> GeoRadiusByMemberWithDistAsync<T>(string key, object member, decimal radius, GeoUnit unit = GeoUnit.m, long? count = null, GeoOrderBy? sorting = null) =>
2774             (await ExecuteScalarAsync(key, (c, k) => c.Value.GeoRadiusBytesByMemberAsync(k, member, radius, unit, count, sorting, false, true, false))).Select(a => (this.DeserializeRedisValueInternal<T>(a.member), a.dist)).ToArray();
2775 
2776         /// <summary>
2777         /// 以给定的成员为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素(包含经度、纬度)。
2778         /// </summary>
2779         /// <param name="key">不含prefix前辍</param>
2780         /// <param name="member">成员</param>
2781         /// <param name="radius">距离</param>
2782         /// <param name="unit">m 表示单位为米;km 表示单位为千米;mi 表示单位为英里;ft 表示单位为英尺;</param>
2783         /// <param name="count">虽然用户可以使用 COUNT 选项去获取前 N 个匹配元素, 但是因为命令在内部可能会需要对所有被匹配的元素进行处理, 所以在对一个非常大的区域进行搜索时, 即使只使用 COUNT 选项去获取少量元素, 命令的执行速度也可能会非常慢。 但是从另一方面来说, 使用 COUNT 选项去减少需要返回的元素数量, 对于减少带宽来说仍然是非常有用的。</param>
2784         /// <param name="sorting">排序</param>
2785         /// <returns></returns>
2786         async private Task<(string member, decimal longitude, decimal latitude)[]> GeoRadiusByMemberWithCoordAsync(string key, object member, decimal radius, GeoUnit unit = GeoUnit.m, long? count = null, GeoOrderBy? sorting = null) =>
2787             (await ExecuteScalarAsync(key, (c, k) => c.Value.GeoRadiusByMemberAsync(k, member, radius, unit, count, sorting, true, false, false))).Select(a => (a.member, a.longitude, a.latitude)).ToArray();
2788         /// <summary>
2789         /// 以给定的成员为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素(包含经度、纬度)。
2790         /// </summary>
2791         /// <param name="key">不含prefix前辍</param>
2792         /// <param name="member">成员</param>
2793         /// <param name="radius">距离</param>
2794         /// <param name="unit">m 表示单位为米;km 表示单位为千米;mi 表示单位为英里;ft 表示单位为英尺;</param>
2795         /// <param name="count">虽然用户可以使用 COUNT 选项去获取前 N 个匹配元素, 但是因为命令在内部可能会需要对所有被匹配的元素进行处理, 所以在对一个非常大的区域进行搜索时, 即使只使用 COUNT 选项去获取少量元素, 命令的执行速度也可能会非常慢。 但是从另一方面来说, 使用 COUNT 选项去减少需要返回的元素数量, 对于减少带宽来说仍然是非常有用的。</param>
2796         /// <param name="sorting">排序</param>
2797         /// <returns></returns>
2798         async private Task<(T member, decimal longitude, decimal latitude)[]> GeoRadiusByMemberWithCoordAsync<T>(string key, object member, decimal radius, GeoUnit unit = GeoUnit.m, long? count = null, GeoOrderBy? sorting = null) =>
2799             (await ExecuteScalarAsync(key, (c, k) => c.Value.GeoRadiusBytesByMemberAsync(k, member, radius, unit, count, sorting, true, false, false))).Select(a => (this.DeserializeRedisValueInternal<T>(a.member), a.longitude, a.latitude)).ToArray();
2800 
2801         /// <summary>
2802         /// 以给定的成员为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素(包含距离、经度、纬度)。
2803         /// </summary>
2804         /// <param name="key">不含prefix前辍</param>
2805         /// <param name="member">成员</param>
2806         /// <param name="radius">距离</param>
2807         /// <param name="unit">m 表示单位为米;km 表示单位为千米;mi 表示单位为英里;ft 表示单位为英尺;</param>
2808         /// <param name="count">虽然用户可以使用 COUNT 选项去获取前 N 个匹配元素, 但是因为命令在内部可能会需要对所有被匹配的元素进行处理, 所以在对一个非常大的区域进行搜索时, 即使只使用 COUNT 选项去获取少量元素, 命令的执行速度也可能会非常慢。 但是从另一方面来说, 使用 COUNT 选项去减少需要返回的元素数量, 对于减少带宽来说仍然是非常有用的。</param>
2809         /// <param name="sorting">排序</param>
2810         /// <returns></returns>
2811         async public Task<(string member, decimal dist, decimal longitude, decimal latitude)[]> GeoRadiusByMemberWithDistAndCoordAsync(string key, object member, decimal radius, GeoUnit unit = GeoUnit.m, long? count = null, GeoOrderBy? sorting = null) =>
2812             (await ExecuteScalarAsync(key, (c, k) => c.Value.GeoRadiusByMemberAsync(k, member, radius, unit, count, sorting, true, true, false))).Select(a => (a.member, a.dist, a.longitude, a.latitude)).ToArray();
2813         /// <summary>
2814         /// 以给定的成员为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素(包含距离、经度、纬度)。
2815         /// </summary>
2816         /// <param name="key">不含prefix前辍</param>
2817         /// <param name="member">成员</param>
2818         /// <param name="radius">距离</param>
2819         /// <param name="unit">m 表示单位为米;km 表示单位为千米;mi 表示单位为英里;ft 表示单位为英尺;</param>
2820         /// <param name="count">虽然用户可以使用 COUNT 选项去获取前 N 个匹配元素, 但是因为命令在内部可能会需要对所有被匹配的元素进行处理, 所以在对一个非常大的区域进行搜索时, 即使只使用 COUNT 选项去获取少量元素, 命令的执行速度也可能会非常慢。 但是从另一方面来说, 使用 COUNT 选项去减少需要返回的元素数量, 对于减少带宽来说仍然是非常有用的。</param>
2821         /// <param name="sorting">排序</param>
2822         /// <returns></returns>
2823         async public Task<(T member, decimal dist, decimal longitude, decimal latitude)[]> GeoRadiusByMemberWithDistAndCoordAsync<T>(string key, object member, decimal radius, GeoUnit unit = GeoUnit.m, long? count = null, GeoOrderBy? sorting = null) =>
2824             (await ExecuteScalarAsync(key, (c, k) => c.Value.GeoRadiusBytesByMemberAsync(k, member, radius, unit, count, sorting, true, true, false))).Select(a => (this.DeserializeRedisValueInternal<T>(a.member), a.dist, a.longitude, a.latitude)).ToArray();
2825         #endregion
2826     }
2827 }
2828 #endif

 

使用方式

 在Startup中注入

在server中使用

 

posted @ 2023-07-25 17:04  .net小峰  阅读(253)  评论(0编辑  收藏  举报