From e465e3db979d4eaa6d68ac57cb637872590ff0a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=87=92=E5=BE=97=E5=8B=A4=E5=BF=AB?= Date: Wed, 12 Jan 2022 13:44:50 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0ConcurrentHashSet?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Masuit.Tools.Abstractions.csproj | 4 +- .../Systems/ConcurrentHashSet.cs | 378 ++++++++++++++++++ .../Systems/ConcurrentLimitedQueue.cs | 4 +- Masuit.Tools.Core/Masuit.Tools.Core.csproj | 4 +- Masuit.Tools.Net45/package.nuspec | 2 +- Masuit.Tools/Masuit.Tools.csproj | 2 +- Masuit.Tools/package.nuspec | 2 +- NetCoreTest/Program.cs | 1 + README.md | 42 +- 9 files changed, 429 insertions(+), 10 deletions(-) create mode 100644 Masuit.Tools.Abstractions/Systems/ConcurrentHashSet.cs diff --git a/Masuit.Tools.Abstractions/Masuit.Tools.Abstractions.csproj b/Masuit.Tools.Abstractions/Masuit.Tools.Abstractions.csproj index 0027b366..ee093bcb 100644 --- a/Masuit.Tools.Abstractions/Masuit.Tools.Abstractions.csproj +++ b/Masuit.Tools.Abstractions/Masuit.Tools.Abstractions.csproj @@ -4,7 +4,7 @@ latest true - 2.4.6.5 + 2.4.7 懒得勤快 Masuit.Tools基础公共库,包含一些常用的操作类,大都是静态类,加密解密,反射操作,Excel简单导出,权重随机筛选算法,分布式短id,表达式树,linq扩展,文件压缩,多线程下载和FTP客户端,硬件信息,字符串扩展方法,日期时间扩展操作,中国农历,大文件拷贝,图像裁剪,验证码,断点续传,集合扩展等常用封装。 懒得勤快,长空X @@ -42,7 +42,7 @@ - + diff --git a/Masuit.Tools.Abstractions/Systems/ConcurrentHashSet.cs b/Masuit.Tools.Abstractions/Systems/ConcurrentHashSet.cs new file mode 100644 index 00000000..78e7fe91 --- /dev/null +++ b/Masuit.Tools.Abstractions/Systems/ConcurrentHashSet.cs @@ -0,0 +1,378 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Runtime.Serialization; +using System.Threading; + +namespace Masuit.Tools.Systems; + +/// +/// 并发HashSet +/// +/// +public sealed class ConcurrentHashSet : ISet, IDisposable +{ + private readonly ReaderWriterLockSlim _lock = new(LockRecursionPolicy.SupportsRecursion); + + private readonly HashSet _hashSet = new(); + + public int Count + { + get + { + _lock.EnterWriteLock(); + try + { + return _hashSet.Count; + } + finally + { + if (_lock.IsWriteLockHeld) + { + _lock.ExitWriteLock(); + } + } + } + } + + public bool IsReadOnly => false; + + public ConcurrentHashSet() + { + } + + public ConcurrentHashSet(IEqualityComparer comparer) + { + _hashSet = new HashSet(comparer); + } + + public ConcurrentHashSet(IEnumerable collection) + { + _hashSet = new HashSet(collection); + } + + public ConcurrentHashSet(IEnumerable collection, IEqualityComparer comparer) + { + _hashSet = new HashSet(collection, comparer); + } + + public ConcurrentHashSet(SerializationInfo info, StreamingContext context) + { + _hashSet = new HashSet(); + var iSerializable = (ISerializable)_hashSet; + iSerializable.GetObjectData(info, context); + } + + public void OnDeserialization(object sender) + { + _hashSet.OnDeserialization(sender); + } + + public void GetObjectData(SerializationInfo info, StreamingContext context) + { + _hashSet.GetObjectData(info, context); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public IEnumerator GetEnumerator() + { + return _hashSet.GetEnumerator(); + } + + public void Add(T item) + { + _lock.EnterWriteLock(); + try + { + _hashSet.Add(item); + } + finally + { + if (_lock.IsWriteLockHeld) + { + _lock.ExitWriteLock(); + } + } + } + + public void UnionWith(IEnumerable other) + { + _lock.EnterWriteLock(); + _lock.EnterReadLock(); + try + { + _hashSet.UnionWith(other); + } + finally + { + if (_lock.IsWriteLockHeld) + { + _lock.ExitWriteLock(); + } + + if (_lock.IsReadLockHeld) + { + _lock.ExitReadLock(); + } + } + } + + public void IntersectWith(IEnumerable other) + { + _lock.EnterWriteLock(); + _lock.EnterReadLock(); + try + { + _hashSet.IntersectWith(other); + } + finally + { + if (_lock.IsWriteLockHeld) + { + _lock.ExitWriteLock(); + } + + if (_lock.IsReadLockHeld) + { + _lock.ExitReadLock(); + } + } + } + + public void ExceptWith(IEnumerable other) + { + _lock.EnterWriteLock(); + _lock.EnterReadLock(); + try + { + _hashSet.ExceptWith(other); + } + finally + { + if (_lock.IsWriteLockHeld) + { + _lock.ExitWriteLock(); + } + + if (_lock.IsReadLockHeld) + { + _lock.ExitReadLock(); + } + } + } + + public void SymmetricExceptWith(IEnumerable other) + { + _lock.EnterWriteLock(); + try + { + _hashSet.SymmetricExceptWith(other); + } + finally + { + if (_lock.IsWriteLockHeld) + { + _lock.ExitWriteLock(); + } + } + } + + public bool IsSubsetOf(IEnumerable other) + { + _lock.EnterWriteLock(); + try + { + return _hashSet.IsSubsetOf(other); + } + finally + { + if (_lock.IsWriteLockHeld) + { + _lock.ExitWriteLock(); + } + } + } + + public bool IsSupersetOf(IEnumerable other) + { + _lock.EnterWriteLock(); + try + { + return _hashSet.IsSupersetOf(other); + } + finally + { + if (_lock.IsWriteLockHeld) + { + _lock.ExitWriteLock(); + } + } + } + + public bool IsProperSupersetOf(IEnumerable other) + { + _lock.EnterWriteLock(); + try + { + return _hashSet.IsProperSupersetOf(other); + } + finally + { + if (_lock.IsWriteLockHeld) + { + _lock.ExitWriteLock(); + } + } + } + + public bool IsProperSubsetOf(IEnumerable other) + { + _lock.EnterWriteLock(); + try + { + return _hashSet.IsProperSubsetOf(other); + } + finally + { + if (_lock.IsWriteLockHeld) + { + _lock.ExitWriteLock(); + } + } + } + + public bool Overlaps(IEnumerable other) + { + _lock.EnterWriteLock(); + try + { + return _hashSet.Overlaps(other); + } + finally + { + if (_lock.IsWriteLockHeld) + { + _lock.ExitWriteLock(); + } + } + } + + public bool SetEquals(IEnumerable other) + { + _lock.EnterWriteLock(); + try + { + return _hashSet.SetEquals(other); + } + finally + { + if (_lock.IsWriteLockHeld) + { + _lock.ExitWriteLock(); + } + } + } + + bool ISet.Add(T item) + { + _lock.EnterWriteLock(); + try + { + return _hashSet.Add(item); + } + finally + { + if (_lock.IsWriteLockHeld) + { + _lock.ExitWriteLock(); + } + } + } + + public void Clear() + { + _lock.EnterWriteLock(); + try + { + _hashSet.Clear(); + } + finally + { + if (_lock.IsWriteLockHeld) + { + _lock.ExitWriteLock(); + } + } + } + + public bool Contains(T item) + { + _lock.EnterWriteLock(); + try + { + return _hashSet.Contains(item); + } + finally + { + if (_lock.IsWriteLockHeld) + { + _lock.ExitWriteLock(); + } + } + } + + public void CopyTo(T[] array, int arrayIndex) + { + _lock.EnterWriteLock(); + try + { + _hashSet.CopyTo(array, arrayIndex); + } + finally + { + if (_lock.IsWriteLockHeld) + { + _lock.ExitWriteLock(); + } + } + } + + public bool Remove(T item) + { + _lock.EnterWriteLock(); + try + { + return _hashSet.Remove(item); + } + finally + { + if (_lock.IsWriteLockHeld) + { + _lock.ExitWriteLock(); + } + } + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + private void Dispose(bool disposing) + { + if (disposing && _lock != null) + { + _lock.Dispose(); + } + } + + ~ConcurrentHashSet() + { + Dispose(false); + } +} diff --git a/Masuit.Tools.Abstractions/Systems/ConcurrentLimitedQueue.cs b/Masuit.Tools.Abstractions/Systems/ConcurrentLimitedQueue.cs index 9e75a08d..f2668a30 100644 --- a/Masuit.Tools.Abstractions/Systems/ConcurrentLimitedQueue.cs +++ b/Masuit.Tools.Abstractions/Systems/ConcurrentLimitedQueue.cs @@ -34,7 +34,7 @@ public ConcurrentLimitedQueue(IEnumerable list) : base(list) } /// - /// + /// /// /// /// @@ -57,4 +57,4 @@ public static implicit operator ConcurrentLimitedQueue(List list) base.Enqueue(item); } } -} \ No newline at end of file +} diff --git a/Masuit.Tools.Core/Masuit.Tools.Core.csproj b/Masuit.Tools.Core/Masuit.Tools.Core.csproj index 4e17a408..dace06c6 100644 --- a/Masuit.Tools.Core/Masuit.Tools.Core.csproj +++ b/Masuit.Tools.Core/Masuit.Tools.Core.csproj @@ -18,7 +18,7 @@ github:https://github.com/ldqk/Masuit.Tools 830c282f-f7c1-42be-8651-4cd06ac8e73f Github True - 2.4.6.5 + 2.4.7 2.4.5.6 masuit.com 2.4.5.6 @@ -31,7 +31,7 @@ github:https://github.com/ldqk/Masuit.Tools - + diff --git a/Masuit.Tools.Net45/package.nuspec b/Masuit.Tools.Net45/package.nuspec index 808f4591..442dfa15 100644 --- a/Masuit.Tools.Net45/package.nuspec +++ b/Masuit.Tools.Net45/package.nuspec @@ -4,7 +4,7 @@ Masuit.Tools.Net45 - 2.4.6.5 + 2.4.7 Masuit.Tools 懒得勤快 diff --git a/Masuit.Tools/Masuit.Tools.csproj b/Masuit.Tools/Masuit.Tools.csproj index de477040..df739365 100644 --- a/Masuit.Tools/Masuit.Tools.csproj +++ b/Masuit.Tools/Masuit.Tools.csproj @@ -166,7 +166,7 @@ 1.5.0 - 6.0.453 + 7.0.473 5.2.7 diff --git a/Masuit.Tools/package.nuspec b/Masuit.Tools/package.nuspec index b183aed1..24920c02 100644 --- a/Masuit.Tools/package.nuspec +++ b/Masuit.Tools/package.nuspec @@ -4,7 +4,7 @@ Masuit.Tools.Net - 2.4.6.5 + 2.4.7 Masuit.Tools 懒得勤快 diff --git a/NetCoreTest/Program.cs b/NetCoreTest/Program.cs index f3b23139..d56a0592 100644 --- a/NetCoreTest/Program.cs +++ b/NetCoreTest/Program.cs @@ -105,6 +105,7 @@ public class ClassCmd public class ClassDto { + [DeserializeOnlyJsonProperty] public string MyProperty { get; set; } public int Num { get; set; } diff --git a/README.md b/README.md index 906a9a62..0d788b1e 100644 --- a/README.md +++ b/README.md @@ -381,6 +381,12 @@ public class MyClass [ComplexPassword]//密码复杂度校验 public string Password { get; set; } + + [EnumOf] // 检测是否是有效枚举值 + public MyEnum MyEnum { get; set; } + + [MinItemsCount(1)] // 检测集合元素最少1个 + public List Strs { get; set; } } ``` ### 21.HTML操作 @@ -452,12 +458,15 @@ string display = MyEnum.Read.GetDisplay();// 获取Display标签的Name属性 var value = typeof(MyEnum).GetValue("Read");//获取字符串表示值对应的枚举值 string enumString = 0.ToEnumString(typeof(MyEnum));// 获取枚举值对应的字符串表示 ``` -### 26.定长队列实现 +### 26.定长队列和ConcurrentHashSet实现 `如果是.NET5及以上,推荐使用框架自带的Channel实现该功能` ```csharp LimitedQueue queue = new LimitedQueue(32);// 声明一个容量为32个元素的定长队列 ConcurrentLimitedQueue queue = new ConcurrentLimitedQueue(32);// 声明一个容量为32个元素的线程安全的定长队列 ``` +```csharp +var set = new ConcurrentHashSet(); // 用法和hashset保持一致 +``` ### 27.反射操作 ```csharp MyClass myClass = new MyClass(); @@ -633,6 +642,11 @@ var stdDev=list.Select(s=>s.ConvertTo()).StandardDeviation(); // 求标准 var pages=queryable.ToPagedList(1,10); // 分页查询 var pages=await queryable.ToPagedListAsync(1,10); // 分页查询 + +var nums=Enumerable.Range(1, 10).ExceptBy(Enumerable.Range(5, 10), i => i); // 按字段取差集 +var nums=Enumerable.Range(1, 10).IntersectBy(Enumerable.Range(5, 10), i => i); // 按字段取交集 +var nums=Enumerable.Range(1, 10).SequenceEqual(Enumerable.Range(5, 10), i => i); // 判断序列相等 +var nums=Enumerable.Range(1, 10).OrderByRandom(); // 随机排序 ``` ### 37.Mime类型 ```csharp @@ -749,6 +763,32 @@ var allchanges=dbContext.GetAllChanges();//获取增删改的实体字段信息 a.Next(func1).Next(func2).Next(func3); "123".Next(s=>s.ToInt32()).Next(x=>x*2).Next(x=>Math.Log(x)); ``` +### 48.Newtonsoft.Json的只允许字段反序列化行为的契约解释器DeserializeOnlyContractResolver +该解释器针对类属性被DeserializeOnlyJsonPropertyAttribute标记的,在反序列化的时候生效,在序列化的时候忽略 +```csharp +public class ClassDto + { + [DeserializeOnlyJsonProperty] + public string MyProperty { get; set; } + + public int Num { get; set; } + } + + JsonConvert.SerializeObject(new MyClass(),new JsonSerializerSettings() + { + ContractResolver = new DeserializeOnlyContractResolver() // 配置使用DeserializeOnlyContractResolver解释器 + }); +``` +如果是WebAPI全局使用: +```csharp + //在Startup.ConfigureServices中 + services.AddMvc().AddNewtonsoftJson(options => + { + var resolver = new DeserializeOnlyContractResolver(); + resolver.NamingStrategy = new CamelCaseNamingStrategy(); + options.SerializerSettings.ContractResolver = resolver; + }); +``` # Asp.Net MVC和Asp.Net Core的支持断点续传和多线程下载的ResumeFileResult