From 95ce7980b638c325a647658e5bd665ae9d96ec1d Mon Sep 17 00:00:00 2001 From: bicijinlian Date: Sat, 17 Dec 2022 23:31:07 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=EF=BC=9A=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E7=BB=91=E5=AE=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../IConfigurationProviderTest.cs | 4 +- OptionStudy.Next/2配置模型/Point.cs | 12 + .../2配置模型/PointTypeConverter.cs | 27 ++ .../3配置绑定/ConfigBinderTest.cs | 265 ++++++++++++++++++ OptionStudy.Next/OptionStudy.Next.csproj | 3 +- OptionStudy.Next/Options/AppOption.cs | 2 +- 6 files changed, 308 insertions(+), 5 deletions(-) create mode 100644 OptionStudy.Next/2配置模型/Point.cs create mode 100644 OptionStudy.Next/2配置模型/PointTypeConverter.cs create mode 100644 OptionStudy.Next/3配置绑定/ConfigBinderTest.cs diff --git a/OptionStudy.Next/2配置模型/IConfigurationProviderTest.cs b/OptionStudy.Next/2配置模型/IConfigurationProviderTest.cs index c0268cb..aff4db7 100644 --- a/OptionStudy.Next/2配置模型/IConfigurationProviderTest.cs +++ b/OptionStudy.Next/2配置模型/IConfigurationProviderTest.cs @@ -58,7 +58,7 @@ namespace OptionStudy.Next Action run = () => { provider.Set("TestName", "UpdateName"); - if (!provider.TryGet("Demo", out string _v)) + if (!provider.TryGet("Demo", out var _v)) { provider.Add("Demo", "demo"); } @@ -88,7 +88,7 @@ namespace OptionStudy.Next }; - var provider = source.Build(null); + var provider = source.Build(new ConfigurationBuilder()); var hasName = provider.TryGet("AppName", out _); Assert.NotNull(provider); diff --git a/OptionStudy.Next/2配置模型/Point.cs b/OptionStudy.Next/2配置模型/Point.cs new file mode 100644 index 0000000..058b59f --- /dev/null +++ b/OptionStudy.Next/2配置模型/Point.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OptionStudy.Next +{ + [TypeConverter(typeof(PointTypeConverter))] + public readonly record struct Point(double x, double y); +} diff --git a/OptionStudy.Next/2配置模型/PointTypeConverter.cs b/OptionStudy.Next/2配置模型/PointTypeConverter.cs new file mode 100644 index 0000000..4746615 --- /dev/null +++ b/OptionStudy.Next/2配置模型/PointTypeConverter.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OptionStudy.Next +{ + public class PointTypeConverter: TypeConverter + { + public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType) + { + return sourceType == typeof(string); + } + + public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value) + { + var split = (value.ToString()??"0.0,0.0").Split(','); + double x = double.Parse(split[0].Trim().TrimStart('(')); + double y = double.Parse(split[1].Trim().TrimEnd(')')); + + return new Point(x, y); + } + } +} diff --git a/OptionStudy.Next/3配置绑定/ConfigBinderTest.cs b/OptionStudy.Next/3配置绑定/ConfigBinderTest.cs new file mode 100644 index 0000000..f63d759 --- /dev/null +++ b/OptionStudy.Next/3配置绑定/ConfigBinderTest.cs @@ -0,0 +1,265 @@ + +using OptionStudy.UnitApp.Next; + +namespace OptionStudy.Next._3配置绑定 +{ + /// + /// 配置绑定 测试 + /// 引用 Microsoft.Extensions.Configuration.Binder 包 + /// + public class ConfigBinderTest : IDisposable + { + private readonly ITestOutputHelper testOutput; + + public ConfigBinderTest(ITestOutputHelper testOutputHelper) + { + this.testOutput = testOutputHelper; + } + + /// + /// 绑定配置项的值 + /// + [Fact] + public void Binder_ConfigItem_Test() + { + IDictionary memoryData = new Dictionary() + { + ["AppName"] = "MemoryAppName", + ["AppVersion"] = "0.0.0.1", + ["EMail:ReceiveAddress"] = "memory@163.com", + ["EMail:Recipient"] = "memory", + ["foo"] = null, + ["bar"] = "", + ["baz"] = "123", + }; + + var root = new ConfigurationBuilder().AddInMemoryCollection(memoryData).Build(); + + //针对 object : 直接返回原始值(字符串或null) + Assert.Null(root.GetValue("foo")); + Assert.Equal(string.Empty, root.GetValue("bar")); + Assert.Equal("123", root.GetValue("baz")); + + + //针对普通类型: 针对类型的 TypeConverter 来 完成类型转换 + Assert.Equal(0,root.GetValue("foo")); + Assert.Equal(123, root.GetValue("baz")); + + //针对 Nullable 类型:原始值为""或null时返回null,否则转换成基础类型。匹配不了了,则借值为 Default(T) + Assert.Null(root.GetValue("foo")); + Assert.Null(root.GetValue("bar")); + + testOutput.WriteLine("绑定配置项的值"); + } + + /// + /// 绑定配置项的值,使用自定义转换器 + /// + [Fact] + public void Binder_ConfigItem_CustomConverter_Test() + { + IDictionary memoryData = new Dictionary() + { + ["Point"] = "(123,456)", + }; + + var root = new ConfigurationBuilder().AddInMemoryCollection(memoryData).Build(); + + var point = root.GetValue("Point"); + + Assert.Equal(123, point.x); + Assert.Equal(456,point.y); + + testOutput.WriteLine("绑定配置项的值,使用自定义转换器"); + } + + /// + /// 绑定复合对象 + /// 自定义的类或结构等对象 + /// + [Fact] + public void Binder_ComplexObject_Test() + { + IDictionary memoryData = new Dictionary() + { + ["AppName"] = "MemoryAppName", + ["AppVersion"] = "0.0.0.1", + ["EMail:ReceiveAddress"] = "memory@163.com", + ["EMail:Recipient"] = "memory", + }; + + var root = new ConfigurationBuilder().AddInMemoryCollection(memoryData).Build(); + + var appOption = root.Get(); + Assert.Equal("MemoryAppName", appOption.AppName); + Assert.Equal("0.0.0.1", appOption.AppVersion.ToString()); + Assert.Equal("memory@163.com", appOption.EMail?.ReceiveAddress); + Assert.Equal("memory", appOption.EMail?.Recipient); + + var email = root.GetSection("EMail").Get(); + Assert.Equal("memory@163.com", email.ReceiveAddress); + Assert.Equal("memory", email.Recipient); + + testOutput.WriteLine("绑定复合对象"); + } + + /// + /// 绑定集合(包括数组) + /// + [Fact] + public void Binder_Set_Test() + { + IDictionary memoryData = new Dictionary() + { + ["0:AppName"] = "MemoryAppName", + ["0:AppVersion"] = "0.0.0.1", + ["0:EMail:ReceiveAddress"] = "memory@163.com", + ["0:EMail:Recipient"] = "memory", + + ["1:AppName"] = "MemoryAppName", + ["1:AppVersion"] = "0.0.0.1", + ["1:EMail:ReceiveAddress"] = "memory@163.com", + ["1:EMail:Recipient"] = "memory", + + ["2;AppName"] = "MemoryAppName", + ["2;AppVersion"] = "0.0.0.1", + ["2;EMail:ReceiveAddress"] = "memory@163.com", + ["2;EMail:Recipient"] = "memory", + }; + + var root = new ConfigurationBuilder().AddInMemoryCollection(memoryData).Build(); + + var appOptions = root.Get>(); + + Assert.Equal("MemoryAppName", appOptions[0].AppName); + Assert.Equal("0.0.0.1", appOptions[0].AppVersion.ToString()); + Assert.Equal("memory@163.com", appOptions[0].EMail?.ReceiveAddress); + Assert.Equal("memory", appOptions[0].EMail?.Recipient); + + Assert.Equal("MemoryAppName", appOptions[1].AppName); + Assert.Equal("0.0.0.1", appOptions[1].AppVersion.ToString()); + Assert.Equal("memory@163.com", appOptions[1].EMail?.ReceiveAddress); + Assert.Equal("memory", appOptions[1].EMail?.Recipient); + + Assert.Equal("MemoryAppName", appOptions[1].AppName); + Assert.Equal("0.0.0.1", appOptions[1].AppVersion.ToString()); + Assert.Equal("memory@163.com", appOptions[1].EMail?.ReceiveAddress); + Assert.Equal("memory", appOptions[1].EMail?.Recipient); + + testOutput.WriteLine("绑定集合(包括数组)"); + } + + /// + /// 绑定集合与数组的差别 + /// 某项绑定失败,不影响其它项绑定,但是数组表现为空项而集合表现为忽略失败项 + /// + [Fact] + public void Binder_CollectionAndArray_Differences_Test() + { + IDictionary memoryData = new Dictionary() + { + ["0:AppName"] = "0MemoryAppName", + ["0:AppVersion"] = "0.0.0.1", + + + ["1:AppName"] = "1MemoryAppName", + ["1:AppVersion"] = "A.B.C.D", //此项改为非版本数值,故意出错 + + ["2:AppName"] = "2MemoryAppName", + ["2:AppVersion"] = "2.1.2.3", + }; + + var root = new ConfigurationBuilder().AddInMemoryCollection(memoryData).Build(); + + var list = root.Get>(); + var array = root.Get(); + + Assert.Equal(2, list.Count); + + Assert.Equal(3, array.Length); + Assert.Null(array[1]); + + testOutput.WriteLine("绑定集合与数组的差别"); + } + + /// + /// 绑定字典 + /// + [Fact] + public void Binder_Dictionary_Test() + { + IDictionary memoryData = new Dictionary() + { + ["One:AppName"] = "0MemoryAppName", + ["One:AppVersion"] = "0.0.0.1", + ["One:EMail:ReceiveAddress"] = "memory@163.com", + ["One:EMail:Recipient"] = "memory", + + + ["Two:AppName"] = "1MemoryAppName", + ["Two:AppVersion"] = "1.2.3.4", + ["Two:EMail:ReceiveAddress"] = "1@163.com", + ["Two:EMail:Recipient"] = "memory1", + + ["Three:AppName"] = "2MemoryAppName", + ["Three:AppVersion"] = "2.0.0.0", + ["Three:EMail:ReceiveAddress"] = "2@163.com", + ["Three:EMail:Recipient"] = "memory2", + }; + + var root = new ConfigurationBuilder().AddInMemoryCollection(memoryData).Build(); + var dic = root.Get>(); + + Assert.Equal(3, dic.Count); + Assert.Equal("0MemoryAppName", dic["One"].AppName); + Assert.Equal("1MemoryAppName", dic["Two"].AppName); + Assert.Equal("2MemoryAppName", dic["Three"].AppName); + + testOutput.WriteLine("绑定字典"); + } + + /// + /// 绑定字典有错 + /// 存在转换错误时,抛出异常 + /// + [Fact] + public void Binder_Dictionary_HasError_Test() + { + IDictionary memoryData = new Dictionary() + { + ["One:AppName"] = "0MemoryAppName", + ["One:AppVersion"] = "0.0.0.1", + ["One:EMail:ReceiveAddress"] = "memory@163.com", + ["One:EMail:Recipient"] = "memory", + + + ["Two:AppName"] = "1MemoryAppName", + ["Two:AppVersion"] = "A.B.C.D", //此项改为非版本数值,故意出错 + ["Two:EMail:ReceiveAddress"] = "1@163.com", + ["Two:EMail:Recipient"] = "memory1", + + ["Three:AppName"] = "2MemoryAppName", + ["Three:AppVersion"] = "2.0.0.0", + ["Three:EMail:ReceiveAddress"] = "2@163.com", + ["Three:EMail:Recipient"] = "memory2", + }; + + var root = new ConfigurationBuilder().AddInMemoryCollection(memoryData).Build(); + + //["Two:AppVersion"] = "A.B.C.D"值不能转换成版本类,会抛出异常 + Action getConfigDic = () => + { + root.Get>(); + }; + + Assert.Throws(getConfigDic); + + testOutput.WriteLine("绑定字典:存在转换错误时,抛出异常!"); + } + + public void Dispose() + { + + } + } +} diff --git a/OptionStudy.Next/OptionStudy.Next.csproj b/OptionStudy.Next/OptionStudy.Next.csproj index 5cf412a..e70c8d7 100644 --- a/OptionStudy.Next/OptionStudy.Next.csproj +++ b/OptionStudy.Next/OptionStudy.Next.csproj @@ -20,7 +20,7 @@ - + @@ -62,7 +62,6 @@ - diff --git a/OptionStudy.Next/Options/AppOption.cs b/OptionStudy.Next/Options/AppOption.cs index 5361222..bd6e307 100644 --- a/OptionStudy.Next/Options/AppOption.cs +++ b/OptionStudy.Next/Options/AppOption.cs @@ -16,7 +16,7 @@ namespace OptionStudy.UnitApp.Next /// /// 软件版本 /// - public string AppVersion { get; set; } = "0.0.0.1"; + public Version AppVersion { get; set; } = new Version( "0.0.0.1"); /// /// 接收邮箱配置对象