高端的扬中网站建设,益阳市建设局网站,银川建设局网站,网站链接加标签我们倾向于将IConfiguration对象转换成一个具体的对象#xff0c;以面向对象的方式来使用配置#xff0c;我们将这个转换过程称为配置绑定。除了将配置树叶子节点配置节的绑定为某种标量对象外#xff0c;我们还可以直接将一个配置节绑定为一个具有对应结构的符合对象。除此…我们倾向于将IConfiguration对象转换成一个具体的对象以面向对象的方式来使用配置我们将这个转换过程称为配置绑定。除了将配置树叶子节点配置节的绑定为某种标量对象外我们还可以直接将一个配置节绑定为一个具有对应结构的符合对象。除此之外配置绑定还支持针对数据、集合和字典类型的绑定。 [507]绑定配置项的值 最简单配置绑定的莫过于针对配置树叶子节点配置节的绑定。这样的配置节承载着原子配置项的值而且这个值是一个字符串所以针对它的配置绑定最终体现为如何将这个字符串转换成指定的目标类型这样的操作体现在IConfiguration接口如下两个GetValue扩展方法上。 public static class ConfigurationBinder
{public static T GetValueT(IConfiguration configuration, string sectionKey);public static T GetValueT(IConfiguration configuration, string sectionKey, T defaultValue);public static object GetValue(IConfiguration configuration, Type type, string sectionKey);public static object GetValue(IConfiguration configuration, Type type, string sectionKey, object defaultValue);
} 对于上面给出的这四个重载的GetValue方法其中两个方法提供了一个表示默认值的参数defaultValue如果对应配置节的值为Null或者空字符串那么指定的默认值将作为方法的返回值。其他两个重载实际上是将Null或者Default(T)作为默认值。这些GetValue方法会将配置节名称对应参数sectionKey作为参数调用指定IConfiguration对象的GetSection方法得到表示对应配置节的IConfigurationSection对象然后将它的Value属性提取出来按照如下规则转换成目标类型。 如果目标类型为object那么直接返回原始值字符串或者Null。如果目标类型不是NullableT那么针对目标类型的TypeConverter将被用来完成类型转换。如果目标类型为NullableT在原始值不是Null或者空字符串的情况下会直接返回Null否则会按照上面的规则将值转换成类型基础T。 为了验证上述这些类型转化规则我们编写了如下测试程序。如代码片段所示我们利用注册的MemoryConfigurationSource添加了三个配置项对应的值分别为Null、空字符串和“123”。在将IConfiguration对象构建出来后我们调用它的GetValueT将三个值转换成Object、Int32和NullableInt32类型。 using Microsoft.Extensions.Configuration;
using System.Diagnostics;var source new Dictionarystring, string?
{[foo] null,[bar] ,[baz] 123
};var root new ConfigurationBuilder().AddInMemoryCollection(source).Build();//针对object
Debug.Assert(root.GetValueobject(foo) null);
Debug.Assert(.Equals(root.GetValueobject(bar)));
Debug.Assert(123.Equals(root.GetValueobject(baz)));//针对普通类型
Debug.Assert(root.GetValueint(foo) 0);
Debug.Assert(root.GetValueint(baz) 123);//针对NullableT
Debug.Assert(root.GetValueint?(foo) null);
Debug.Assert(root.GetValueint?(bar) null); [508]类型转换器在配置绑定中的应用 按照前面介绍的类型转换规则如果目标类型支持源自字符串的类型转换就能够将配置项的原始值绑定为该类型的对象。在下面的代码片段中我们定义了一个表示二维坐标的Point记录Record并且为它注册了一个针对PointTypeConverter的类型转换器。PointTypeConverter通过实现的ConvertFrom方法将坐标的字符串表达式如“123”和“456”转换成一个Point对象。 [TypeConverter(typeof(PointTypeConverter))]
public readonly record struct Point(double X, double Y);public class PointTypeConverter : TypeConverter
{public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType) 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);}
} 由于定义的Point类型支持源自字符串的类型转换所以如果配置项的原始值字符串具有与之兼容的格式我们就可以按照如下方式将其绑定为一个Point对象。 using App;
using Microsoft.Extensions.Configuration;
using System.Diagnostics;var source new Dictionarystring, string
{[point] (123,456)
};var root new ConfigurationBuilder().AddInMemoryCollection(source).Build();var point root.GetValuePoint(point);
Debug.Assert(point.X 123);
Debug.Assert(point.Y 456); [509]复合对象的配置绑定 这里所谓的复合类型就是一个具有属性数据成员的自定义类型。如果用一棵树表示一个复合对象那么叶子节点承载所有的数据并且叶子节点的数据类型均为基元类型。如果用数据字典来提供一个复杂对象所有的原始数据那么这个字典中只需要包含叶子节点对应的值即可。我们只要将叶子节点所在的路径作为字典元素的Key就可以通过一个字典对象体现复合对象的结构。 public readonly record struct Profile(Gender Gender, int Age, ContactInfo ContactInfo);
public readonly record struct ContactInfo(string EmailAddress, string PhoneNo);
public enum Gender
{Male,Female
} 上面的代码片段定义了一个表示个人基本信息的Profile记录它的Gender、Age和ContactInfo属性分别表示性别、年龄和联系方式。表示联系方式的ContactInfo记录定义了EmailAddress和PhoneNo属性分别表示电子邮箱地址和电话号码。一个完整的Profile对象可以通过图1所示的树来体现。 图1 复杂对象的配置树 如果需要通过配置的形式表示一个完整的Profile对象只需要提供四个叶子节点性别、年龄、电子邮箱地址和电话号码对应的配置数据配置字典只需要按照表1来存储这四个键值对就可以了。 表1 针对复杂对象的配置数据结构 Key Value Gender Male Age 18 ContactInfo:Email foobaroutlook.com ContactInfo:PhoneNo 123456789 我们通过下面的程序来验证针对复合数据类型的绑定。我们先创建一个ConfigurationBuilder对象并利用注册的MemoryConfigurationSource对象添加了表5-2所示的配置数据。在构建出IConfiguration对象之后我们调用它的GetT扩展方法将其绑定为Profile对象。 using App;
using Microsoft.Extensions.Configuration;
using System.Diagnostics;var source new Dictionarystring, string
{[gender] Male,[age] 18,[contactInfo:emailAddress] foobaroutlook.com,[contactInfo:phoneNo] 123456789
};var configuration new ConfigurationBuilder().AddInMemoryCollection(source).Build();var profile configuration.GetProfile();
Debug.Assert(profile.Gender Gender.Male);
Debug.Assert(profile.Age 18);
Debug.Assert(profile.ContactInfo.EmailAddress foobaroutlook.com);
Debug.Assert(profile.ContactInfo.PhoneNo 123456789); [510]集合的配置绑定 如果配置绑定的目标类型是一个集合包括数组那么当前IConfiguration对象的每个子配置节将绑定为集合的元素。如果目标类型为元素类型为Profile的集合那么配置树应该具有图2所示的结构。既然能够正确地将集合对象通过一个合法的配置树体现出来那么就可以将它转换成配置字典 图2 集合对象的配置树 我们利用如下的实例来演示针对集合的配置绑定。如代码片段所示我们创建了一个ConfigurationBuilder对象并为它注册了一个MemoryConfigurationSource对象并利用注册的MemoryConfigurationSource对象添加了配置数据。在构建出IConfiguration对象之后我们调用它的GetT扩展方法将它分别绑定为一个IListProfile和Profile数组对象。 using App;
using Microsoft.Extensions.Configuration;
using System.Diagnostics;var source new Dictionarystring, string
{[0:gender] Male,[0:age] 18,[0:contactInfo:emailAddress] foooutlook.com,[0:contactInfo:phoneNo] 123,[1:gender] Male,[1:age] 25,[1:contactInfo:emailAddress] baroutlook.com,[1:contactInfo:phoneNo] 456,[2:gender] Female,[2:age] 36,[2:contactInfo:emailAddress] bazoutlook.com,[2:contactInfo:phoneNo] 789
};var configuration new ConfigurationBuilder().AddInMemoryCollection(source).Build();var list configuration.GetIListProfile();
Debug.Assert(list[0].ContactInfo.EmailAddress foooutlook.com);
Debug.Assert(list[1].ContactInfo.EmailAddress baroutlook.com);
Debug.Assert(list[2].ContactInfo.EmailAddress bazoutlook.com);var array configuration.GetProfile[]();
Debug.Assert(array[0].ContactInfo.EmailAddress foooutlook.com);
Debug.Assert(array[1].ContactInfo.EmailAddress baroutlook.com);
Debug.Assert(array[2].ContactInfo.EmailAddress bazoutlook.com); [511]集合和数组的配置绑定的差异 针对集合的配置绑定不会因为某个元素的绑定失败而终止。如果目标类型是数组最终绑定生成的数组长度与子配置节的个数总是一致的。如果目标类型是列表将不会生成对应的元素。我们将上面演示程序做了稍许的修改将第一个元素的性别从“Male”改为“男”那么针对这个Profile元素绑定将会失败。如果将目标类型设置为IEnumerableProfile那么最终生成的集合只有两个元素。倘若目标类型切换成Profile数组数组的长度依然为3但是第一个元素是空。 using App;
using Microsoft.Extensions.Configuration;
using System.Diagnostics;var source new Dictionarystring, string
{[0:gender] 男,[0:age] 18,[0:contactInfo:emailAddress] foooutlook.com,[0:contactInfo:phoneNo] 123,[1:gender] Male,[1:age] 25,[1:contactInfo:emailAddress] baroutlook.com,[1:contactInfo:phoneNo] 456,[2:gender] Female,[2:age] 36,[2:contactInfo:emailAddress] bazoutlook.com,[2:contactInfo:phoneNo] 789
};var configuration new ConfigurationBuilder().AddInMemoryCollection(source).Build();var list configuration.GetIListProfile();
Debug.Assert(list.Count 2);
Debug.Assert(list[0].ContactInfo.EmailAddress baroutlook.com);
Debug.Assert(list[1].ContactInfo.EmailAddress bazoutlook.com);var array configuration.GetProfile[]();
Debug.Assert(array.Length 3);
Debug.Assert(array[0] default);
Debug.Assert(array[1].ContactInfo.EmailAddress baroutlook.com);
Debug.Assert(array[2].ContactInfo.EmailAddress bazoutlook.com); [512]字典的配置绑定 能够通过配置绑定生成的字典是一个实现了IDictionarystring,T的类型它Key必须是一个字符串或者枚举。如果采用配置树的形式表示这样一个字典对象就会发现它与针对集合的配置树在结构上几乎是一样的唯一的区别是集合元素的索引直接变成字典元素的Key。也就是说图2所示的配置树同样可以表示成一个具有三个元素的Dictionarystring, Profile对象它们对应的Key分别“0”、“1”和“2”所以我们可以按照如下方式将承载相同结构数据的IConfiguration对象绑定为一个IDictionarystring, Profile 对象。如代码片段所示我们将表示集合索引的整数“0”、“1”和“2”改成普通的字符串“foo”、“bar”和“baz”。 using App;
using Microsoft.Extensions.Configuration;
using System.Diagnostics;var source new Dictionarystring, string
{[foo:gender] Male,[foo:age] 18,[foo:contactInfo:emailAddress] foooutlook.com,[foo:contactInfo:phoneNo] 123,[bar:gender] Male,[bar:age] 25,[bar:contactInfo:emailAddress] baroutlook.com,[bar:contactInfo:phoneNo] 456,[baz:gender] Female,[baz:age] 36,[baz:contactInfo:emailAddress] bazoutlook.com,[baz:contactInfo:phoneNo] 789
};var profiles new ConfigurationBuilder().AddInMemoryCollection(source).Build().GetIDictionarystring,Profile();;Debug.Assert(profiles[foo].ContactInfo.EmailAddress foooutlook.com);
Debug.Assert(profiles[bar].ContactInfo.EmailAddress baroutlook.com);
Debug.Assert(profiles[baz].ContactInfo.EmailAddress bazoutlook.com);