فهرست منبع

增加可空key的字典类型

懒得勤快 3 سال پیش
والد
کامیت
0ae435bf70

+ 14 - 13
Masuit.Tools.Abstractions/Extensions/BaseType/IDictionaryExtensions.cs

@@ -2,6 +2,7 @@
 using System.Collections.Concurrent;
 using System.Collections.Generic;
 using System.Threading.Tasks;
+using Masuit.Tools.Systems;
 
 namespace Masuit.Tools
 {
@@ -309,7 +310,7 @@ namespace Masuit.Tools
         /// <param name="source"></param>
         /// <param name="keySelector">键选择器</param>
         /// <returns></returns>
-        public static Dictionary<TKey, TSource> ToDictionarySafety<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
+        public static NullableDictionary<TKey, TSource> ToDictionarySafety<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
         {
             var dic = new Dictionary<TKey, TSource>();
             foreach (var item in source)
@@ -330,9 +331,9 @@ namespace Masuit.Tools
         /// <param name="keySelector">键选择器</param>
         /// <param name="elementSelector">值选择器</param>
         /// <returns></returns>
-        public static Dictionary<TKey, TElement> ToDictionarySafety<TSource, TKey, TElement>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector)
+        public static NullableDictionary<TKey, TElement> ToDictionarySafety<TSource, TKey, TElement>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector)
         {
-            var dic = new Dictionary<TKey, TElement>();
+            var dic = new NullableDictionary<TKey, TElement>();
             foreach (var item in source)
             {
                 dic[keySelector(item)] = elementSelector(item);
@@ -351,9 +352,9 @@ namespace Masuit.Tools
         /// <param name="keySelector">键选择器</param>
         /// <param name="elementSelector">值选择器</param>
         /// <returns></returns>
-        public static async Task<IDictionary<TKey, TElement>> ToDictionarySafetyAsync<TSource, TKey, TElement>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, Task<TElement>> elementSelector)
+        public static async Task<NullableConcurrentDictionary<TKey, TElement>> ToDictionarySafetyAsync<TSource, TKey, TElement>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, Task<TElement>> elementSelector)
         {
-            var dic = new ConcurrentDictionary<TKey, TElement>();
+            var dic = new NullableConcurrentDictionary<TKey, TElement>();
             await source.ForeachAsync(async item => dic[keySelector(item)] = await elementSelector(item));
             return dic;
         }
@@ -367,9 +368,9 @@ namespace Masuit.Tools
         /// <param name="source"></param>
         /// <param name="keySelector">键选择器</param>
         /// <returns></returns>
-        public static ConcurrentDictionary<TKey, TSource> ToConcurrentDictionary<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
+        public static NullableConcurrentDictionary<TKey, TSource> ToConcurrentDictionary<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
         {
-            var dic = new ConcurrentDictionary<TKey, TSource>();
+            var dic = new NullableConcurrentDictionary<TKey, TSource>();
             foreach (var item in source)
             {
                 dic[keySelector(item)] = item;
@@ -388,9 +389,9 @@ namespace Masuit.Tools
         /// <param name="keySelector">键选择器</param>
         /// <param name="elementSelector">值选择器</param>
         /// <returns></returns>
-        public static ConcurrentDictionary<TKey, TElement> ToConcurrentDictionary<TSource, TKey, TElement>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector)
+        public static NullableConcurrentDictionary<TKey, TElement> ToConcurrentDictionary<TSource, TKey, TElement>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector)
         {
-            var dic = new ConcurrentDictionary<TKey, TElement>();
+            var dic = new NullableConcurrentDictionary<TKey, TElement>();
             foreach (var item in source)
             {
                 dic[keySelector(item)] = elementSelector(item);
@@ -409,7 +410,7 @@ namespace Masuit.Tools
         /// <param name="keySelector">键选择器</param>
         /// <param name="elementSelector">值选择器</param>
         /// <returns></returns>
-        public static async Task<ConcurrentDictionary<TKey, TElement>> ToConcurrentDictionaryAsync<TSource, TKey, TElement>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, Task<TElement>> elementSelector)
+        public static async Task<NullableConcurrentDictionary<TKey, TElement>> ToConcurrentDictionaryAsync<TSource, TKey, TElement>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, Task<TElement>> elementSelector)
         {
             var dic = new ConcurrentDictionary<TKey, TElement>();
             await source.ForeachAsync(async item => dic[keySelector(item)] = await elementSelector(item));
@@ -423,7 +424,7 @@ namespace Masuit.Tools
         /// <typeparam name="TValue"></typeparam>
         /// <param name="dic"></param>
         /// <returns></returns>
-        public static ConcurrentDictionary<TKey, TValue> AsConcurrentDictionary<TKey, TValue>(this Dictionary<TKey, TValue> dic) => new(dic);
+        public static NullableConcurrentDictionary<TKey, TValue> AsConcurrentDictionary<TKey, TValue>(this Dictionary<TKey, TValue> dic) => dic;
 
         /// <summary>
         /// 转换成普通字典集合
@@ -432,6 +433,6 @@ namespace Masuit.Tools
         /// <typeparam name="TValue"></typeparam>
         /// <param name="dic"></param>
         /// <returns></returns>
-        public static Dictionary<TKey, TValue> AsDictionary<TKey, TValue>(this ConcurrentDictionary<TKey, TValue> dic) => new(dic);
+        public static NullableDictionary<TKey, TValue> AsDictionary<TKey, TValue>(this ConcurrentDictionary<TKey, TValue> dic) => dic;
     }
-}
+}

+ 1 - 1
Masuit.Tools.Abstractions/Masuit.Tools.Abstractions.csproj

@@ -4,7 +4,7 @@
     <LangVersion>latest</LangVersion>
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
     <CodeAnalysisRuleSet />
-    <Version>2.4.7.1</Version>
+    <Version>2.4.7.2</Version>
     <Authors>懒得勤快</Authors>
     <Description>Masuit.Tools基础公共库,包含一些常用的操作类,大都是静态类,加密解密,反射操作,Excel简单导出,权重随机筛选算法,分布式短id,表达式树,linq扩展,文件压缩,多线程下载和FTP客户端,硬件信息,字符串扩展方法,日期时间扩展操作,中国农历,大文件拷贝,图像裁剪,验证码,断点续传,集合扩展等常用封装。</Description>
     <Copyright>懒得勤快,长空X</Copyright>

+ 104 - 0
Masuit.Tools.Abstractions/Systems/NullObject.cs

@@ -0,0 +1,104 @@
+using System.ComponentModel;
+
+namespace Masuit.Tools.Systems;
+
+/// <summary>
+/// 可空对象
+/// </summary>
+/// <typeparam name="T"></typeparam>
+public readonly struct NullObject<T>
+{
+    [DefaultValue(true)]
+    private readonly bool _isnull;
+
+    private NullObject(T item, bool isnull) : this()
+    {
+        _isnull = isnull;
+        Item = item;
+    }
+
+    public NullObject(T item) : this(item, item == null)
+    {
+    }
+
+    public static NullObject<T> Null()
+    {
+        return new NullObject<T>();
+    }
+
+    public T Item { get; }
+
+    /// <summary>
+    /// 是否是null
+    /// </summary>
+    /// <returns></returns>
+    public bool IsNull()
+    {
+        return _isnull;
+    }
+
+    /// <summary>
+    /// 隐式转换
+    /// </summary>
+    /// <param name="nullObject"></param>
+    public static implicit operator T(NullObject<T> nullObject)
+    {
+        return nullObject.Item;
+    }
+
+    /// <summary>
+    /// 隐式转换
+    /// </summary>
+    /// <param name="item"></param>
+    public static implicit operator NullObject<T>(T item)
+    {
+        return new NullObject<T>(item);
+    }
+
+    public override string ToString()
+    {
+        return (Item != null) ? Item.ToString() : "NULL";
+    }
+
+    public override bool Equals(object obj)
+    {
+        if (obj == null)
+        {
+            return IsNull();
+        }
+
+        if (obj is not NullObject<T> nullObject)
+        {
+            return false;
+        }
+
+        if (IsNull())
+        {
+            return nullObject.IsNull();
+        }
+
+        if (nullObject.IsNull())
+        {
+            return false;
+        }
+
+        return Item.Equals(nullObject.Item);
+    }
+
+    public override int GetHashCode()
+    {
+        if (_isnull)
+        {
+            return 0;
+        }
+
+        var result = Item.GetHashCode();
+
+        if (result >= 0)
+        {
+            result++;
+        }
+
+        return result;
+    }
+}

+ 72 - 0
Masuit.Tools.Abstractions/Systems/NullableConcurrentDictionary.cs

@@ -0,0 +1,72 @@
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+
+namespace Masuit.Tools.Systems;
+
+/// <summary>
+/// 支持null-key和value的字典类型
+/// </summary>
+/// <typeparam name="TKey"></typeparam>
+/// <typeparam name="TValue"></typeparam>
+public class NullableConcurrentDictionary<TKey, TValue> : ConcurrentDictionary<NullObject<TKey>, TValue>
+{
+    public NullableConcurrentDictionary() : base()
+    {
+    }
+
+    public NullableConcurrentDictionary(int concurrencyLevel, int capacity) : base(concurrencyLevel, capacity)
+    {
+    }
+
+    public NullableConcurrentDictionary(IEqualityComparer<NullObject<TKey>> comparer) : base(comparer)
+    {
+    }
+
+    public new TValue this[NullObject<TKey> key]
+    {
+        get => TryGetValue(key, out var value) ? value : default;
+        set => base[key] = value;
+    }
+
+    /// <summary>
+    /// 隐式转换
+    /// </summary>
+    /// <param name="dic"></param>
+    public static implicit operator NullableConcurrentDictionary<TKey, TValue>(Dictionary<TKey, TValue> dic)
+    {
+        var nullableDictionary = new NullableConcurrentDictionary<TKey, TValue>();
+        foreach (var p in dic)
+        {
+            nullableDictionary[p.Key] = p.Value;
+        }
+        return nullableDictionary;
+    }
+
+    /// <summary>
+    /// 隐式转换
+    /// </summary>
+    /// <param name="dic"></param>
+    public static implicit operator NullableConcurrentDictionary<TKey, TValue>(ConcurrentDictionary<TKey, TValue> dic)
+    {
+        var nullableDictionary = new NullableConcurrentDictionary<TKey, TValue>();
+        foreach (var p in dic)
+        {
+            nullableDictionary[p.Key] = p.Value;
+        }
+        return nullableDictionary;
+    }
+
+    /// <summary>
+    /// 隐式转换
+    /// </summary>
+    /// <param name="dic"></param>
+    public static implicit operator ConcurrentDictionary<TKey, TValue>(NullableConcurrentDictionary<TKey, TValue> dic)
+    {
+        var newdic = new ConcurrentDictionary<TKey, TValue>();
+        foreach (var p in dic)
+        {
+            newdic[p.Key] = p.Value;
+        }
+        return newdic;
+    }
+}

+ 84 - 0
Masuit.Tools.Abstractions/Systems/NullableDictionary.cs

@@ -0,0 +1,84 @@
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+
+namespace Masuit.Tools.Systems;
+
+/// <summary>
+/// 支持null-key和value的字典类型
+/// </summary>
+/// <typeparam name="TKey"></typeparam>
+/// <typeparam name="TValue"></typeparam>
+public class NullableDictionary<TKey, TValue> : Dictionary<NullObject<TKey>, TValue>
+{
+    public NullableDictionary() : base()
+    {
+    }
+
+    public NullableDictionary(int capacity) : base(capacity)
+    {
+    }
+
+    public NullableDictionary(IEqualityComparer<NullObject<TKey>>? comparer) : base(comparer)
+    {
+    }
+
+    public NullableDictionary(int capacity, IEqualityComparer<NullObject<TKey>> comparer) : base(capacity, comparer)
+    {
+    }
+
+    public NullableDictionary(IDictionary<NullObject<TKey>, TValue> dictionary) : base(dictionary)
+    {
+    }
+
+    public NullableDictionary(IDictionary<NullObject<TKey>, TValue> dictionary, IEqualityComparer<NullObject<TKey>> comparer) : base(dictionary, comparer)
+    {
+    }
+
+    public new TValue this[NullObject<TKey> key]
+    {
+        get => TryGetValue(key, out var value) ? value : default;
+        set => base[key] = value;
+    }
+
+    /// <summary>
+    /// 隐式转换
+    /// </summary>
+    /// <param name="dic"></param>
+    public static implicit operator NullableDictionary<TKey, TValue>(Dictionary<TKey, TValue> dic)
+    {
+        var nullableDictionary = new NullableDictionary<TKey, TValue>();
+        foreach (var p in dic)
+        {
+            nullableDictionary[p.Key] = p.Value;
+        }
+        return nullableDictionary;
+    }
+
+    /// <summary>
+    /// 隐式转换
+    /// </summary>
+    /// <param name="dic"></param>
+    public static implicit operator NullableDictionary<TKey, TValue>(ConcurrentDictionary<TKey, TValue> dic)
+    {
+        var nullableDictionary = new NullableDictionary<TKey, TValue>();
+        foreach (var p in dic)
+        {
+            nullableDictionary[p.Key] = p.Value;
+        }
+        return nullableDictionary;
+    }
+
+    /// <summary>
+    /// 隐式转换
+    /// </summary>
+    /// <param name="dic"></param>
+    public static implicit operator Dictionary<TKey, TValue>(NullableDictionary<TKey, TValue> dic)
+    {
+        var newdic = new Dictionary<TKey, TValue>();
+        foreach (var p in dic)
+        {
+            newdic[p.Key] = p.Value;
+        }
+        return newdic;
+    }
+}

+ 1 - 1
Masuit.Tools.Core/Masuit.Tools.Core.csproj

@@ -18,7 +18,7 @@ github:https://github.com/ldqk/Masuit.Tools
         <UserSecretsId>830c282f-f7c1-42be-8651-4cd06ac8e73f</UserSecretsId>
         <RepositoryType>Github</RepositoryType>
         <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
-        <Version>2.4.7.1</Version>
+        <Version>2.4.7.2</Version>
         <FileVersion>2.4.5.6</FileVersion>
         <Company>masuit.com</Company>
         <AssemblyVersion>2.4.5.6</AssemblyVersion>

+ 9 - 0
Masuit.Tools.Net45/Masuit.Tools.Net45.csproj

@@ -277,6 +277,15 @@
     <Compile Include="..\Masuit.Tools.Abstractions\Systems\LimitedQueue.cs">
       <Link>Systems\LimitedQueue.cs</Link>
     </Compile>
+    <Compile Include="..\Masuit.Tools.Abstractions\Systems\NullableConcurrentDictionary.cs">
+      <Link>Systems\NullableConcurrentDictionary.cs</Link>
+    </Compile>
+    <Compile Include="..\Masuit.Tools.Abstractions\Systems\NullableDictionary.cs">
+      <Link>Systems\NullableDictionary.cs</Link>
+    </Compile>
+    <Compile Include="..\Masuit.Tools.Abstractions\Systems\NullObject.cs">
+      <Link>Systems\NullObject.cs</Link>
+    </Compile>
     <Compile Include="..\Masuit.Tools.Abstractions\Systems\SnowFlake.cs">
       <Link>Systems\SnowFlake.cs</Link>
     </Compile>

+ 1 - 1
Masuit.Tools.Net45/package.nuspec

@@ -4,7 +4,7 @@
     <!--*-->
     <id>Masuit.Tools.Net45</id>
     <!--*-->
-    <version>2.4.7.1</version>
+    <version>2.4.7.2</version>
     <title>Masuit.Tools</title>
     <!--*-->
     <authors>懒得勤快</authors>

+ 9 - 0
Masuit.Tools/Masuit.Tools.csproj

@@ -112,6 +112,15 @@
     <Compile Include="..\Masuit.Tools.Abstractions\Systems\*.*">
       <Link>Systems\%(RecursiveDir)%(FileName)%(Extension)</Link>
     </Compile>
+    <Compile Include="..\Masuit.Tools.Abstractions\Systems\NullableConcurrentDictionary.cs">
+      <Link>Systems\NullableConcurrentDictionary.cs</Link>
+    </Compile>
+    <Compile Include="..\Masuit.Tools.Abstractions\Systems\NullableDictionary.cs">
+      <Link>Systems\NullableDictionary.cs</Link>
+    </Compile>
+    <Compile Include="..\Masuit.Tools.Abstractions\Systems\NullObject.cs">
+      <Link>Systems\NullObject.cs</Link>
+    </Compile>
     <Compile Include="..\Masuit.Tools.Abstractions\Validator\*.*">
       <Link>Validator\%(RecursiveDir)%(FileName)%(Extension)</Link>
     </Compile>

+ 1 - 1
Masuit.Tools/package.nuspec

@@ -4,7 +4,7 @@
     <!--*-->
     <id>Masuit.Tools.Net</id>
     <!--*-->
-    <version>2.4.7.1</version>
+    <version>2.4.7.2</version>
     <title>Masuit.Tools</title>
     <!--*-->
     <authors>懒得勤快</authors>

+ 3 - 0
README.md

@@ -800,6 +800,9 @@ public class ClassDto
         }
 ```
 	
+### 49. 可空key的字典类型
+NullableConcurrentDictionary和NullableDictionary  
+用法和普通的字典类型保持一致,相比于普通的字典类型,其key是可以为null的,并且索引器获取时,如果key不存在,是不会报错的,会get到value类型的默认值。
 	
 # Asp.Net MVC和Asp.Net Core的支持断点续传和多线程下载的ResumeFileResult