From 6a2a09514b11efa3c8bbb5361c933ac0b7a03084 Mon Sep 17 00:00:00 2001 From: Ogoun Date: Thu, 12 Dec 2019 21:00:37 +0300 Subject: [PATCH] Update 1. CollectionFactory - create ienumerable and array in runtime 2. Configuration.Bind - map config to custom config class --- ConfigurationTests/AppConfig.cs | 21 +++++ ConfigurationTests/ConfigurationTests.csproj | 18 ++++ ConfigurationTests/Program.cs | 27 ++++++ ConfigurationTests/config.ini | 14 +++ ZeroLevel.sln | 14 +++ .../Services/Collections/CollectionFactory.cs | 89 +++++++++++++++++++ .../Services/Config/BaseConfiguration.cs | 67 ++++++++++++++ .../Services/Config/BaseConfigurationSet.cs | 5 ++ ZeroLevel/Services/Config/IConfiguration.cs | 2 + .../Services/Config/IConfigurationSet.cs | 2 + ZeroLevel/Services/Reflection/TypeHelpers.cs | 5 ++ 11 files changed, 264 insertions(+) create mode 100644 ConfigurationTests/AppConfig.cs create mode 100644 ConfigurationTests/ConfigurationTests.csproj create mode 100644 ConfigurationTests/Program.cs create mode 100644 ConfigurationTests/config.ini create mode 100644 ZeroLevel/Services/Collections/CollectionFactory.cs diff --git a/ConfigurationTests/AppConfig.cs b/ConfigurationTests/AppConfig.cs new file mode 100644 index 0000000..a959cee --- /dev/null +++ b/ConfigurationTests/AppConfig.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; + +namespace ConfigurationTests +{ + public class AppConfig + { + public string Url; + public int BatchSize; + public IEnumerable Sheme; + public IEnumerable Port; + public ServiceConfig Service; + } + + public class ServiceConfig + { + public string AppName; + public string AppKey; + public string ServiceGroup; + public string ServiceType; + } +} diff --git a/ConfigurationTests/ConfigurationTests.csproj b/ConfigurationTests/ConfigurationTests.csproj new file mode 100644 index 0000000..ebe4228 --- /dev/null +++ b/ConfigurationTests/ConfigurationTests.csproj @@ -0,0 +1,18 @@ + + + + Exe + netcoreapp3.1 + + + + + + + + + Always + + + + diff --git a/ConfigurationTests/Program.cs b/ConfigurationTests/Program.cs new file mode 100644 index 0000000..199adc4 --- /dev/null +++ b/ConfigurationTests/Program.cs @@ -0,0 +1,27 @@ +using System; +using ZeroLevel; + +namespace ConfigurationTests +{ + class Program + { + + static void Main(string[] args) + { + var config = Configuration.ReadFromIniFile("config.ini").Bind(); + Console.WriteLine(config.Url); + Console.WriteLine(config.BatchSize); + Console.WriteLine("Ports"); + foreach (var port in config.Port) + { + Console.WriteLine($"\t{port}"); + } + Console.WriteLine("Shemes"); + foreach (var sheme in config.Sheme) + { + Console.WriteLine($"\t{sheme}"); + } + Console.ReadKey(); + } + } +} diff --git a/ConfigurationTests/config.ini b/ConfigurationTests/config.ini new file mode 100644 index 0000000..97392c2 --- /dev/null +++ b/ConfigurationTests/config.ini @@ -0,0 +1,14 @@ +url=https://habr.ru +batchSize=1000 +sheme=socks +sheme=http +sheme=https +port=80 +port=90 +port=8800 + +[service] +AppName=TestApp +AppKey=test.app +ServiceGroup=seo +ServiceType=site \ No newline at end of file diff --git a/ZeroLevel.sln b/ZeroLevel.sln index adb699f..aa575be 100644 --- a/ZeroLevel.sln +++ b/ZeroLevel.sln @@ -31,6 +31,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ZeroLevel.SQL", "ZeroLevel. EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZeroNetworkMonitor", "ZeroNetworkMonitor\ZeroNetworkMonitor.csproj", "{EECF6EA0-6D9C-4B69-9CA3-23357C04B84C}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConfigurationTests", "ConfigurationTests\ConfigurationTests.csproj", "{E37785CE-E75A-49FB-B17F-16A0F2C6D656}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -185,6 +187,18 @@ Global {EECF6EA0-6D9C-4B69-9CA3-23357C04B84C}.Release|x64.Build.0 = Release|Any CPU {EECF6EA0-6D9C-4B69-9CA3-23357C04B84C}.Release|x86.ActiveCfg = Release|Any CPU {EECF6EA0-6D9C-4B69-9CA3-23357C04B84C}.Release|x86.Build.0 = Release|Any CPU + {E37785CE-E75A-49FB-B17F-16A0F2C6D656}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E37785CE-E75A-49FB-B17F-16A0F2C6D656}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E37785CE-E75A-49FB-B17F-16A0F2C6D656}.Debug|x64.ActiveCfg = Debug|Any CPU + {E37785CE-E75A-49FB-B17F-16A0F2C6D656}.Debug|x64.Build.0 = Debug|Any CPU + {E37785CE-E75A-49FB-B17F-16A0F2C6D656}.Debug|x86.ActiveCfg = Debug|Any CPU + {E37785CE-E75A-49FB-B17F-16A0F2C6D656}.Debug|x86.Build.0 = Debug|Any CPU + {E37785CE-E75A-49FB-B17F-16A0F2C6D656}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E37785CE-E75A-49FB-B17F-16A0F2C6D656}.Release|Any CPU.Build.0 = Release|Any CPU + {E37785CE-E75A-49FB-B17F-16A0F2C6D656}.Release|x64.ActiveCfg = Release|Any CPU + {E37785CE-E75A-49FB-B17F-16A0F2C6D656}.Release|x64.Build.0 = Release|Any CPU + {E37785CE-E75A-49FB-B17F-16A0F2C6D656}.Release|x86.ActiveCfg = Release|Any CPU + {E37785CE-E75A-49FB-B17F-16A0F2C6D656}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/ZeroLevel/Services/Collections/CollectionFactory.cs b/ZeroLevel/Services/Collections/CollectionFactory.cs new file mode 100644 index 0000000..f5bbde0 --- /dev/null +++ b/ZeroLevel/Services/Collections/CollectionFactory.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using ZeroLevel.Services.Invokation; + +namespace ZeroLevel.Services.Collections +{ + public interface ICollectionBuilder + { + void Append(object item); + IEnumerable Complete(); + } + public interface IArrayBuilder + { + void Set(object item, int index); + object Complete(); + } + public class CollectionFactory + { + public static ICollectionBuilder Create() => Create(typeof(T)); + + public static ICollectionBuilder Create(Type type) + { + return new IEnumerableBuilder(type); + } + + public static IArrayBuilder CreateArray(int count) => CreateArray(typeof(T), count); + + public static IArrayBuilder CreateArray(Type type, int count) + { + return new ArrayBuilder(type, count); + } + + private class IEnumerableBuilder + : ICollectionBuilder + { + private readonly IInvokeWrapper _wrapper; + + private readonly Invoker _insert; + private readonly object _instance; + + public IEnumerableBuilder(Type entityType) + { + _wrapper = InvokeWrapper.Create(); + var genericType = typeof(List<>); + var instanceType = genericType.MakeGenericType(new Type[] { entityType }); + _instance = Activator.CreateInstance(instanceType); + + var insert_key = _wrapper.Configure(instanceType, "Add").Single(); + _insert = _wrapper.GetInvoker(insert_key); + } + + public void Append(object item) + { + _insert.Invoke(_instance, new object[] { item }); + } + + public IEnumerable Complete() + { + return (IEnumerable)_instance; + } + } + + private class ArrayBuilder + : IArrayBuilder + { + private readonly IInvokeWrapper _wrapper; + + private readonly Invoker _insert; + private readonly object _instance; + + public ArrayBuilder(Type entityType, int count) + { + _instance = Array.CreateInstance(entityType, count); + } + + public void Set(object item, int index) + { + ((Array)_instance).SetValue(item, index); + } + + public object Complete() + { + return _instance; + } + } + } +} diff --git a/ZeroLevel/Services/Config/BaseConfiguration.cs b/ZeroLevel/Services/Config/BaseConfiguration.cs index d8f81fc..a82fa26 100644 --- a/ZeroLevel/Services/Config/BaseConfiguration.cs +++ b/ZeroLevel/Services/Config/BaseConfiguration.cs @@ -2,6 +2,9 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Globalization; +using System.Linq; +using ZeroLevel.Services.Collections; +using ZeroLevel.Services.ObjectMapping; using ZeroLevel.Services.Reflection; using ZeroLevel.Services.Serialization; @@ -459,5 +462,69 @@ namespace ZeroLevel.Services.Config config.Append(key, this[key]); } } + + public T Bind() + { + var mapper = TypeMapper.Create(true); + var instance = (T)TypeHelpers.CreateInitialState(typeof(T)); + mapper.TraversalMembers(member => + { + if (Contains(member.Name)) + { + int count = Count(member.Name); + switch (count) + { + case 0: return; + case 1: // field + member.Setter(instance, First(member.Name)); + break; + default: // array, or first + if (TypeHelpers.IsArray(member.ClrType)) + { + var itemType = member.ClrType.GetElementType(); + if (itemType == typeof(string)) + { + var array = Items(member.Name).ToArray(); + member.Setter(instance, array); + } + else + { + var arrayBuilder = CollectionFactory.CreateArray(itemType, count); + int index = 0; + foreach (var item in Items(member.Name)) + { + arrayBuilder.Set(StringToTypeConverter.TryConvert(item, itemType), index); + index++; + } + member.Setter(instance, arrayBuilder.Complete()); + } + } + else if (TypeHelpers.IsEnumerable(member.ClrType)) + { + var itemType = member.ClrType.GenericTypeArguments.First(); + if (itemType == typeof(string)) + { + member.Setter(instance, Items(member.Name)); + } + else + { + var collectionBuilder = CollectionFactory.Create(itemType); + foreach (var item in Items(member.Name)) + { + collectionBuilder.Append(StringToTypeConverter.TryConvert(item, itemType)); + } + member.Setter(instance, collectionBuilder.Complete()); + } + } + else + { + member.Setter(instance, First(member.Name)); + } + break; + } + } + }); + return instance; + } } } \ No newline at end of file diff --git a/ZeroLevel/Services/Config/BaseConfigurationSet.cs b/ZeroLevel/Services/Config/BaseConfigurationSet.cs index e2a3aca..3aacf2a 100644 --- a/ZeroLevel/Services/Config/BaseConfigurationSet.cs +++ b/ZeroLevel/Services/Config/BaseConfigurationSet.cs @@ -257,5 +257,10 @@ namespace ZeroLevel.Services.Config set[sectionName].CopyTo(section); } } + + public T Bind() + { + return default; + } } } \ No newline at end of file diff --git a/ZeroLevel/Services/Config/IConfiguration.cs b/ZeroLevel/Services/Config/IConfiguration.cs index 7f3b27d..fb986af 100644 --- a/ZeroLevel/Services/Config/IConfiguration.cs +++ b/ZeroLevel/Services/Config/IConfiguration.cs @@ -141,5 +141,7 @@ namespace ZeroLevel #endregion Create, Clean, Delete void CopyTo(IConfiguration config); + + T Bind(); } } \ No newline at end of file diff --git a/ZeroLevel/Services/Config/IConfigurationSet.cs b/ZeroLevel/Services/Config/IConfigurationSet.cs index c2e7c1b..f54d068 100644 --- a/ZeroLevel/Services/Config/IConfigurationSet.cs +++ b/ZeroLevel/Services/Config/IConfigurationSet.cs @@ -91,5 +91,7 @@ namespace ZeroLevel void Merge(IConfigurationSet set); #endregion Methods + + T Bind(); } } \ No newline at end of file diff --git a/ZeroLevel/Services/Reflection/TypeHelpers.cs b/ZeroLevel/Services/Reflection/TypeHelpers.cs index 092931f..c1679f3 100644 --- a/ZeroLevel/Services/Reflection/TypeHelpers.cs +++ b/ZeroLevel/Services/Reflection/TypeHelpers.cs @@ -186,6 +186,11 @@ namespace ZeroLevel.Services.Reflection return FormatterServices.GetUninitializedObject(type); } + public static Type GetArrayType(Type elementType) + { + return elementType.MakeArrayType(); + } + public static object CreateNonInitializedInstance(Type type) { if (type == null)