Tools.Collections
Changes
.gitignore 21(+21 -0)
src/Tools.Collections/Tools.Collections.ConcurrentDictonary.Extensions/ConcurrentDictionaryExtensions.cs 56(+56 -0)
src/Tools.Collections/Tools.Collections.ConcurrentDictonary.Extensions/Tools.Collections.Concurrent.Extensions.csproj 9(+9 -0)
src/Tools.Collections/Tools.Collections.ConsoleTest/Test_SortedDictionarySortKeyItemKey.cs 46(+46 -0)
src/Tools.Collections/Tools.Collections.LinkItemDictionary/Tools.Collections.Concurrent.LinkItemDictionary.csproj 6(+3 -3)
src/Tools.Collections/Tools.Collections.ObjectLinkItemDictionary/ObjectLinkItemDictionary.cs 105(+56 -49)
src/Tools.Collections/Tools.Collections.ObjectLinkItemDictionary/Tools.Collections.Concurrent.ObjectLinkItemDictionary.csproj 17(+17 -0)
src/Tools.Collections/Tools.Collections.sln 60(+60 -0)
src/Tools.Collections/Tools.Collections.SortedDictionarySortKeyItemKey/SortedDictionaryComparer.cs 123(+123 -0)
Details
.gitignore 21(+21 -0)
diff --git a/.gitignore b/.gitignore
index bbefd19..73f686c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,3 +9,24 @@ src/ManagetLinkCollection/ManagetLinkCollection/bin/*
src/ManagetLinkCollection/ManagetLinkCollection/obj/*
src/ManagetLinkCollection/packages/*
+
+
+
+src/Tools.Collections/.vs/*
+/.vs/*
+
+src/Tools.Collections/Tools.Collections.ConcurrentDictonary.Extensions/bin/*
+src/Tools.Collections/Tools.Collections.ConcurrentDictonary.Extensions/obj/*
+
+src/Tools.Collections/Tools.Collections.LinkItemDictionary/bin/*
+src/Tools.Collections/Tools.Collections.LinkItemDictionary/obj/*
+
+src/Tools.Collections/Tools.Collections.ObjectLinkItemDictionary/bin/*
+src/Tools.Collections/Tools.Collections.ObjectLinkItemDictionary/obj/*
+
+src/Tools.Collections/Tools.Collections.SortedDictionarySortKeyItemKey/bin/*
+src/Tools.Collections/Tools.Collections.SortedDictionarySortKeyItemKey/obj/*
+
+src/Tools.Collections/Tools.Collections.ConsoleTest/bin/*
+src/Tools.Collections/Tools.Collections.ConsoleTest/obj/*
+
diff --git a/src/Tools.Collections/Tools.Collections.ConcurrentDictonary.Extensions/ConcurrentDictionaryExtensions.cs b/src/Tools.Collections/Tools.Collections.ConcurrentDictonary.Extensions/ConcurrentDictionaryExtensions.cs
new file mode 100644
index 0000000..d78ecd9
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.ConcurrentDictonary.Extensions/ConcurrentDictionaryExtensions.cs
@@ -0,0 +1,56 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using System.Collections.Concurrent;
+
+namespace Tools.Collections.Concurrent.Extensions
+{
+
+ public static class ConcurrentDictionaryExtensions
+ {
+ /// <typeparam name="TKey">Item Key</typeparam>
+ /// <typeparam name="TData">Data Type</typeparam>
+ /// <param name="key">key</param>
+ /// <param name="removeExpression">Remove if true</param>
+ public static void RemoveIf<TKey, TData>(
+ this ConcurrentDictionary<TKey, IValueWrapper<TData>> dictionary,
+ TKey key,
+ Func<IValueWrapper<TData>, bool> removeExpression
+ )
+ {
+ var collection = (ICollection<KeyValuePair<TKey, IValueWrapper<TData>>>) dictionary;
+
+ collection
+ .Remove(
+ new KeyValuePair<TKey, IValueWrapper<TData>>(
+ key,
+ new RemoveExpressionItem<TData>(removeExpression)
+ )
+ );
+ }
+
+ /// <typeparam name="TKey">Item Key</typeparam>
+ /// <typeparam name="TData">Data Type</typeparam>
+ /// <param name="key">key</param>
+ /// <param name="removeExpression">Remove if true</param>
+ public static void RemoveIf<TKey, TData>(
+ this ICollection<KeyValuePair<TKey, IValueWrapper<TData>>> collection,
+ TKey key,
+ Func<IValueWrapper<TData>, bool> removeExpression
+ )
+ {
+ collection
+ .Remove(
+ new KeyValuePair<TKey, IValueWrapper<TData>>(
+ key,
+ new RemoveExpressionItem<TData>(removeExpression)
+ )
+ );
+ }
+
+ }
+
+}
diff --git a/src/Tools.Collections/Tools.Collections.ConcurrentDictonary.Extensions/IValueWrapper.cs b/src/Tools.Collections/Tools.Collections.ConcurrentDictonary.Extensions/IValueWrapper.cs
new file mode 100644
index 0000000..6a7d5a6
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.ConcurrentDictonary.Extensions/IValueWrapper.cs
@@ -0,0 +1,80 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tools.Collections.Concurrent.Extensions
+{
+ public interface IValueWrapper<TValue>
+ {
+ TValue Value { get; }
+ }
+
+ public sealed class RealItemWrapper<TValue>
+ : IValueWrapper<TValue>
+ {
+ public TValue Value { private set; get; }
+
+
+ public RealItemWrapper(TValue value)
+ {
+ Value = value;
+ }
+
+ public override int GetHashCode()
+ {
+ return Value.GetHashCode();
+ }
+
+ public override bool Equals(object obj)
+ {
+ switch (obj)
+ {
+ case null:
+ return false;
+
+ case RealItemWrapper<TValue> item:
+ return
+ Value.Equals(item.Value);
+
+ case RemoveExpressionItem<TValue> item:
+ return
+ item.NeedRemoveExpression(this);
+
+ default:
+ return false;
+ }
+ }
+
+ }
+
+ internal sealed class RemoveExpressionItem<TValue>
+ : IValueWrapper<TValue>
+ {
+ public TValue Value => default(TValue);
+
+ public Func<IValueWrapper<TValue>, bool> NeedRemoveExpression { private set; get; }
+
+
+ public RemoveExpressionItem(Func<IValueWrapper<TValue>, bool> func)
+ {
+ NeedRemoveExpression = func;
+ }
+
+
+ public override bool Equals(object obj)
+ {
+ switch (obj)
+ {
+ case IValueWrapper<TValue> item:
+ return NeedRemoveExpression(item);
+
+ default:
+ return false;
+ }
+ }
+ }
+
+
+}
diff --git a/src/Tools.Collections/Tools.Collections.ConcurrentDictonary.Extensions/Tools.Collections.Concurrent.Extensions.csproj b/src/Tools.Collections/Tools.Collections.ConcurrentDictonary.Extensions/Tools.Collections.Concurrent.Extensions.csproj
new file mode 100644
index 0000000..111f0b5
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.ConcurrentDictonary.Extensions/Tools.Collections.Concurrent.Extensions.csproj
@@ -0,0 +1,9 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <PropertyGroup>
+ <TargetFramework>netstandard1.1</TargetFramework>
+ <AssemblyName>Tools.Collections.Concurrent.Extensions</AssemblyName>
+ <RootNamespace>Tools.Collections.Concurrent.Extensions</RootNamespace>
+ </PropertyGroup>
+
+</Project>
diff --git a/src/Tools.Collections/Tools.Collections.ConsoleTest/Test_SortedDictionarySortKeyItemKey.cs b/src/Tools.Collections/Tools.Collections.ConsoleTest/Test_SortedDictionarySortKeyItemKey.cs
new file mode 100644
index 0000000..9d5c9cb
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.ConsoleTest/Test_SortedDictionarySortKeyItemKey.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using Tools.Collections;
+
+namespace Tools.Collections.ConsoleTest
+{
+ class Test_SortedDictionarySortKeyItemKey
+ {
+ public void Test()
+ {
+ var set = new SortedDictionarySortKeyItemKey<DateTime, Guid, Guid>(
+ new SortedDictionaryComparer<DateTime, Guid>()
+ {
+ TSortKeyIsUnique = true
+ }
+ );
+
+ var now = DateTime.Now;
+ var id1 = Guid.NewGuid();
+ var id2 = Guid.NewGuid();
+
+
+ set.Add(
+ new AddSortedItem<DateTime, Guid>(now, id1),
+ id1
+ );
+ set.Add(
+ new AddSortedItem<DateTime, Guid>(now, id2),
+ id2
+ );
+
+ Console.WriteLine(set.Count);
+
+ Console.WriteLine(set[new GetSortedItem<DateTime, Guid>(id1)]);
+ Console.WriteLine(set[new GetSortedItem<DateTime, Guid>(id2)]);
+
+ Console.WriteLine("end");
+
+ set.Remove(new GetSortedItem<DateTime, Guid>(id1));
+ }
+ }
+}
diff --git a/src/Tools.Collections/Tools.Collections.LinkItemDictionary/LinkItemDictionary.cs b/src/Tools.Collections/Tools.Collections.LinkItemDictionary/LinkItemDictionary.cs
new file mode 100644
index 0000000..31c729c
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.LinkItemDictionary/LinkItemDictionary.cs
@@ -0,0 +1,179 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using System.Collections.Concurrent;
+
+using Tools.Collections.Concurrent.Extensions;
+
+namespace Tools.Collections.Concurrent
+{
+
+ /// <summary>
+ /// Thread safe key value link-item collection.
+ /// Item remove if link count is 0.
+ /// Base on ConcurrentDictionary.
+ /// </summary>
+ public class LinkItemDictionary<TKey, TData>
+ {
+
+ #region
+
+ public IReadOnlyDictionary<TKey, IValueWrapper<LinkItem<TKey, TData>>> Storage { private set; get; }
+
+
+ private readonly ConcurrentDictionary<TKey, IValueWrapper<LinkItem<TKey, TData>>> _Storage
+ = new ConcurrentDictionary<TKey, IValueWrapper<LinkItem<TKey, TData>>>();
+
+ private readonly ICollection<KeyValuePair<TKey, IValueWrapper<LinkItem<TKey, TData>>>> _StorageAsCollection;
+
+ #endregion
+
+
+ #region
+
+ public LinkItemDictionary()
+ {
+ Storage = (IReadOnlyDictionary<TKey, IValueWrapper<LinkItem<TKey, TData>>>)_Storage;
+ _StorageAsCollection = _Storage;
+ }
+
+ #endregion
+
+
+ #region
+
+ /// <summary>
+ /// Add link. Add or update Value
+ /// </summary>
+ public LinkItem<TKey, TData> AddLink(
+ TKey key,
+ Func<TKey, TData> addFactory,
+ Func<LinkItem<TKey, TData>, TData> updateFactory
+ )
+ {
+ return _Storage.AddOrUpdate(
+ key,
+ (TKey k) =>
+ {
+ return
+ new RealItemWrapper<LinkItem<TKey, TData>>(
+ new LinkItem<TKey, TData>
+ (
+ key,
+ 1,
+ addFactory != null ? addFactory(key) : default(TData)
+ )
+ );
+ },
+ (TKey k, IValueWrapper<LinkItem<TKey, TData>> old_value) =>
+ {
+ return
+ new RealItemWrapper<LinkItem<TKey, TData>>(
+ new LinkItem<TKey, TData>(
+ key,
+ old_value.Value.LinkCount + 1,
+ updateFactory != null
+ ? updateFactory(old_value.Value)
+ : old_value.Value.Value
+ )
+ );
+ }
+ )
+ .Value;
+ }
+
+ /// <summary>
+ /// Add link. Add Value
+ /// </summary>
+ public LinkItem<TKey, TData> AddLink(
+ TKey key,
+ Func<TKey, TData> addFactory)
+ {
+ return AddLink(key, addFactory, null);
+ }
+
+ /// <summary>
+ /// Add link. Update value if exsist
+ /// </summary>
+ public LinkItem<TKey, TData> AddLink(
+ TKey key,
+ Func<LinkItem<TKey, TData>, TData> updateFactory)
+ {
+ return AddLink(key, null, updateFactory);
+ }
+
+ /// <summary>
+ /// Add link. No change value
+ /// </summary>
+ public LinkItem<TKey, TData> AddLink(
+ TKey key
+ )
+ {
+ return AddLink(key, null, null);
+ }
+
+
+ /// <summary>
+ /// Remove link. Update value
+ /// </summary>
+ public LinkItem<TKey, TData> RemoveLink(
+ TKey key,
+ Func<LinkItem<TKey, TData>, TData> updateFactory)
+ {
+ var item = _Storage.AddOrUpdate(
+ key,
+ (TKey k) =>
+ {
+ return
+ new RealItemWrapper<LinkItem<TKey, TData>>(
+ new LinkItem<TKey, TData>(
+ key,
+ 0,
+ default(TData)
+ )
+ );
+ },
+ (TKey k, IValueWrapper<LinkItem<TKey, TData>> old_value) =>
+ {
+ return
+ new RealItemWrapper<LinkItem<TKey, TData>>(
+ new LinkItem<TKey, TData>(
+ key,
+ old_value.Value.LinkCount - 1,
+ updateFactory != null
+ ? updateFactory(old_value.Value)
+ : old_value.Value.Value
+ )
+ );
+ }
+ );
+
+ if (item.Value.LinkCount == 0)
+ {
+ _StorageAsCollection.RemoveIf(
+ key,
+ (value) =>
+ {
+ return value.Value.LinkCount == 0;
+ }
+ );
+ }
+
+ return item.Value;
+ }
+
+ /// <summary>
+ /// Remove link. No change value if not remove
+ /// </summary>
+ public LinkItem<TKey, TData> RemoveLink(TKey key)
+ {
+ return RemoveLink(key, null);
+ }
+
+ #endregion
+
+ }
+}
diff --git a/src/Tools.Collections/Tools.Collections.ObjectLinkItemDictionary/Tools.Collections.Concurrent.ObjectLinkItemDictionary.csproj b/src/Tools.Collections/Tools.Collections.ObjectLinkItemDictionary/Tools.Collections.Concurrent.ObjectLinkItemDictionary.csproj
new file mode 100644
index 0000000..ace8172
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.ObjectLinkItemDictionary/Tools.Collections.Concurrent.ObjectLinkItemDictionary.csproj
@@ -0,0 +1,17 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <PropertyGroup>
+ <TargetFramework>netstandard1.1</TargetFramework>
+ <AssemblyName>Tools.Collections.Concurrent.ObjectLinkItemDictionary</AssemblyName>
+ <RootNamespace>Tools.Collections.Concurrent</RootNamespace>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <PackageReference Include="System.Collections.Immutable" Version="1.7.1" />
+ </ItemGroup>
+
+ <ItemGroup>
+ <ProjectReference Include="..\Tools.Collections.LinkItemDictionary\Tools.Collections.Concurrent.LinkItemDictionary.csproj" />
+ </ItemGroup>
+
+</Project>
src/Tools.Collections/Tools.Collections.sln 60(+60 -0)
diff --git a/src/Tools.Collections/Tools.Collections.sln b/src/Tools.Collections/Tools.Collections.sln
new file mode 100644
index 0000000..72e2819
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.sln
@@ -0,0 +1,60 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30503.244
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tools.Collections.ConsoleTest", "Tools.Collections.ConsoleTest\Tools.Collections.ConsoleTest.csproj", "{181D7F46-CEDB-4BBB-86A6-DA91EB0F539D}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Lib", "Lib", "{E674A5DB-8D7A-4650-9D6B-B1881F5B57B4}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{4762CF50-BA4B-443A-954A-803E4CEF6451}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tools.Collections.Concurrent.Extensions", "Tools.Collections.ConcurrentDictonary.Extensions\Tools.Collections.Concurrent.Extensions.csproj", "{7531E7FD-16D7-4111-8FBD-D98F23D7C53C}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tools.Collections.SortedDictionarySortKeyItemKey", "Tools.Collections.SortedDictionarySortKeyItemKey\Tools.Collections.SortedDictionarySortKeyItemKey.csproj", "{83C77E76-7114-4494-A7D3-6B4D54767AC6}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tools.Collections.Concurrent.LinkItemDictionary", "Tools.Collections.LinkItemDictionary\Tools.Collections.Concurrent.LinkItemDictionary.csproj", "{E221963A-526E-43C1-A6D5-BF4D9721BC59}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tools.Collections.Concurrent.ObjectLinkItemDictionary", "Tools.Collections.ObjectLinkItemDictionary\Tools.Collections.Concurrent.ObjectLinkItemDictionary.csproj", "{0792B9B8-BBB9-4421-81A1-A534B43CA6B8}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {181D7F46-CEDB-4BBB-86A6-DA91EB0F539D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {181D7F46-CEDB-4BBB-86A6-DA91EB0F539D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {181D7F46-CEDB-4BBB-86A6-DA91EB0F539D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {181D7F46-CEDB-4BBB-86A6-DA91EB0F539D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7531E7FD-16D7-4111-8FBD-D98F23D7C53C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7531E7FD-16D7-4111-8FBD-D98F23D7C53C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7531E7FD-16D7-4111-8FBD-D98F23D7C53C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7531E7FD-16D7-4111-8FBD-D98F23D7C53C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {83C77E76-7114-4494-A7D3-6B4D54767AC6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {83C77E76-7114-4494-A7D3-6B4D54767AC6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {83C77E76-7114-4494-A7D3-6B4D54767AC6}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {83C77E76-7114-4494-A7D3-6B4D54767AC6}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E221963A-526E-43C1-A6D5-BF4D9721BC59}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E221963A-526E-43C1-A6D5-BF4D9721BC59}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E221963A-526E-43C1-A6D5-BF4D9721BC59}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E221963A-526E-43C1-A6D5-BF4D9721BC59}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0792B9B8-BBB9-4421-81A1-A534B43CA6B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0792B9B8-BBB9-4421-81A1-A534B43CA6B8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0792B9B8-BBB9-4421-81A1-A534B43CA6B8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0792B9B8-BBB9-4421-81A1-A534B43CA6B8}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {181D7F46-CEDB-4BBB-86A6-DA91EB0F539D} = {4762CF50-BA4B-443A-954A-803E4CEF6451}
+ {7531E7FD-16D7-4111-8FBD-D98F23D7C53C} = {E674A5DB-8D7A-4650-9D6B-B1881F5B57B4}
+ {83C77E76-7114-4494-A7D3-6B4D54767AC6} = {E674A5DB-8D7A-4650-9D6B-B1881F5B57B4}
+ {E221963A-526E-43C1-A6D5-BF4D9721BC59} = {E674A5DB-8D7A-4650-9D6B-B1881F5B57B4}
+ {0792B9B8-BBB9-4421-81A1-A534B43CA6B8} = {E674A5DB-8D7A-4650-9D6B-B1881F5B57B4}
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {C32931BC-9551-4A06-9A76-F7E4F162B3C7}
+ EndGlobalSection
+EndGlobal
diff --git a/src/Tools.Collections/Tools.Collections.SortedDictionarySortKeyItemKey/BaseSortedItem.cs b/src/Tools.Collections/Tools.Collections.SortedDictionarySortKeyItemKey/BaseSortedItem.cs
new file mode 100644
index 0000000..2d12e52
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.SortedDictionarySortKeyItemKey/BaseSortedItem.cs
@@ -0,0 +1,80 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tools.Collections
+{
+ public abstract class BaseSortedItem<TSortKey, TItemKey>
+ {
+ public TSortKey SortKey { private set; get; }
+ public TItemKey ItemKey { private set; get; }
+
+ public BaseSortedItem(TSortKey sortKey)
+ {
+ SortKey = sortKey;
+ }
+ public BaseSortedItem(TItemKey itemKey)
+ {
+ ItemKey = itemKey;
+ }
+
+ public BaseSortedItem(TSortKey sortKey, TItemKey itemKey)
+ {
+ SortKey = sortKey;
+ ItemKey = itemKey;
+ }
+
+
+ public override int GetHashCode()
+ {
+ return ItemKey.GetHashCode();
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj == null)
+ {
+ return false;
+ }
+
+ var typedObj = (BaseSortedItem<TSortKey, TItemKey>)obj;
+ return ItemKey.Equals(typedObj.ItemKey);
+ }
+
+ public override string ToString()
+ {
+ return ItemKey.ToString();
+ }
+ }
+
+ /// <summary>
+ /// Use for add to SortedDictionary
+ /// </summary>
+ /// <typeparam name="TSortKey"></typeparam>
+ /// <typeparam name="TItemKey"></typeparam>
+ public sealed class AddSortedItem<TSortKey, TItemKey>
+ : BaseSortedItem<TSortKey, TItemKey>
+ {
+ public AddSortedItem(TSortKey sortKey, TItemKey itemKey)
+ : base(sortKey, itemKey)
+ {
+ }
+ }
+
+ /// <summary>
+ /// Use for get from SortedDictionary
+ /// </summary>
+ /// <typeparam name="TSortKey"></typeparam>
+ /// <typeparam name="TItemKey"></typeparam>
+ public sealed class GetSortedItem<TSortKey, TItemKey>
+ : BaseSortedItem<TSortKey, TItemKey>
+ {
+ public GetSortedItem(TItemKey itemKey)
+ : base(itemKey)
+ {
+ }
+ }
+
+}
diff --git a/src/Tools.Collections/Tools.Collections.SortedDictionarySortKeyItemKey/SortedDictionaryComparer.cs b/src/Tools.Collections/Tools.Collections.SortedDictionarySortKeyItemKey/SortedDictionaryComparer.cs
new file mode 100644
index 0000000..25288ac
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.SortedDictionarySortKeyItemKey/SortedDictionaryComparer.cs
@@ -0,0 +1,123 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tools.Collections
+{
+ public abstract class BaseSortedDictionaryComparer<TSortKey, TItemKey>
+ : IComparer<BaseSortedItem<TSortKey, TItemKey>>
+ {
+ protected readonly Func<TSortKey, TSortKey, int> SortKeyComparer;
+ protected readonly Func<TItemKey, TItemKey, int> ItemKeyComparer;
+
+ /// <summary>
+ /// TSortKey is unique values only
+ /// </summary>
+ public bool TSortKeyIsUnique { set; get; }
+
+
+ protected BaseSortedDictionaryComparer(
+ Func<TSortKey, TSortKey, int> sortKeyComparer,
+ Func<TItemKey, TItemKey, int> itemKeyComparer
+ )
+ {
+ SortKeyComparer = sortKeyComparer;
+ ItemKeyComparer = itemKeyComparer;
+ }
+
+
+ public int Compare(
+ BaseSortedItem<TSortKey, TItemKey> x,
+ BaseSortedItem<TSortKey, TItemKey> y
+ )
+ {
+ if (x is GetSortedItem<TSortKey, TItemKey>)
+ {
+ return ItemKeyComparer(x.ItemKey, y.ItemKey);
+ }
+ else
+ {
+ var compareRes = SortKeyComparer(x.SortKey, y.SortKey);
+
+ if (
+ compareRes != 0
+ || TSortKeyIsUnique
+ )
+ {
+ return compareRes;
+ }
+
+ return ItemKeyComparer(x.ItemKey, y.ItemKey);
+ }
+ }
+ }
+
+
+ public class SortedDictionaryComparer_SortKeyItemKey<TSortKey, TItemKey>
+ : BaseSortedDictionaryComparer<TSortKey, TItemKey>
+ {
+ public SortedDictionaryComparer_SortKeyItemKey(
+ IComparer<TSortKey> sortKeyComparer,
+ IComparer<TItemKey> itemKeyComparer
+ )
+ : base(
+ sortKeyComparer.Compare,
+ itemKeyComparer.Compare
+ )
+ {
+ }
+
+ }
+
+ public class SortedDictionaryComparer_SortKey<TSortKey, TItemKey>
+ : BaseSortedDictionaryComparer<TSortKey, TItemKey>
+ where TSortKey : IComparable<TSortKey>
+ {
+ public SortedDictionaryComparer_SortKey(
+ IComparer<TItemKey> itemKeyComparer
+ )
+ : base(
+ (TSortKey tk1, TSortKey tk2) => tk1.CompareTo(tk2),
+ itemKeyComparer.Compare
+ )
+ {
+ }
+
+ }
+
+ public class SortedDictionaryComparer_TItemKey<TSortKey, TItemKey>
+ : BaseSortedDictionaryComparer<TSortKey, TItemKey>
+ where TItemKey : IComparable<TItemKey>
+ {
+ public SortedDictionaryComparer_TItemKey(
+ IComparer<TSortKey> sortKeyComparer
+ )
+ : base(
+ sortKeyComparer.Compare,
+ (TItemKey ti1, TItemKey ti2) => ti1.CompareTo(ti2)
+ )
+ {
+ }
+
+ }
+
+
+ public class SortedDictionaryComparer<TSortKey, TItemKey>
+ : BaseSortedDictionaryComparer<TSortKey, TItemKey>
+ where TItemKey : IComparable<TItemKey>
+ where TSortKey : IComparable<TSortKey>
+ {
+ public SortedDictionaryComparer()
+ : base(
+ (TSortKey tk1, TSortKey tk2) => tk1.CompareTo(tk2),
+ (TItemKey ti1, TItemKey ti2) => ti1.CompareTo(ti2)
+ )
+ {
+ }
+
+ }
+
+
+}
diff --git a/src/Tools.Collections/Tools.Collections.SortedDictionarySortKeyItemKey/SortedDictionarySortKeyItemKey.cs b/src/Tools.Collections/Tools.Collections.SortedDictionarySortKeyItemKey/SortedDictionarySortKeyItemKey.cs
new file mode 100644
index 0000000..373daa9
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.SortedDictionarySortKeyItemKey/SortedDictionarySortKeyItemKey.cs
@@ -0,0 +1,54 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using System.Collections;
+
+namespace Tools.Collections
+{
+
+ /// <summary>
+ /// Sort by TSortKey, Get item by TItemKey.
+ ///
+ /// To add item use KeyEntity: Tools.Collections.SortedDictionarySortKeyItemKey.AddSortedItem.
+ /// To get item use KeyEntity: Tools.Collections.SortedDictionarySortKeyItemKey.GetSortedItem.
+ /// </summary>
+ /// <typeparam name="TSortKey">Key for sorting</typeparam>
+ /// <typeparam name="TItemKey">Key for item</typeparam>
+ /// <typeparam name="TValue">Value</typeparam>
+ public class SortedDictionarySortKeyItemKey<TSortKey, TItemKey, TValue>
+ : SortedDictionary<BaseSortedItem<TSortKey, TItemKey>, TValue>
+ {
+ private BaseSortedDictionaryComparer<TSortKey, TItemKey> SpecialComparer =>
+ (BaseSortedDictionaryComparer<TSortKey, TItemKey>)Comparer;
+
+ /// <summary>
+ /// TSortKey is unique values only
+ /// </summary>
+ public bool TSortKeyIsUnique
+ {
+ set => SpecialComparer.TSortKeyIsUnique = value;
+ get => SpecialComparer.TSortKeyIsUnique;
+ }
+
+ public SortedDictionarySortKeyItemKey(
+ BaseSortedDictionaryComparer<TSortKey, TItemKey> comparer
+ ) : base(
+ comparer
+ )
+ {
+ }
+
+ public SortedDictionarySortKeyItemKey(
+ IDictionary<BaseSortedItem<TSortKey, TItemKey>, TValue> dictionary,
+ BaseSortedDictionaryComparer<TSortKey, TItemKey> comparer
+ ) : base(
+ dictionary,
+ comparer
+ )
+ {
+ }
+ }
+}
diff --git a/src/Tools.Collections/Tools.Collections.SortedDictionarySortKeyItemKey/Tools.Collections.SortedDictionarySortKeyItemKey.csproj b/src/Tools.Collections/Tools.Collections.SortedDictionarySortKeyItemKey/Tools.Collections.SortedDictionarySortKeyItemKey.csproj
new file mode 100644
index 0000000..833194f
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.SortedDictionarySortKeyItemKey/Tools.Collections.SortedDictionarySortKeyItemKey.csproj
@@ -0,0 +1,8 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <PropertyGroup>
+ <TargetFramework>netstandard1.0</TargetFramework>
+ <RootNamespace>Tools.Collections</RootNamespace>
+ </PropertyGroup>
+
+</Project>