将IConfiguration对象转换成一个具体的对象,以面向对象的方式来使用配置

我们倾向于将IConfiguration对象转换成一个具体的对象,以面向对象的方式来使用配置,我们将这个转换过程称为配置绑定。除了将配置树叶子节点配置节的绑定为某种标量对象外,我们还可以直接将一个配置节绑定为一个具有对应结构的符合对象。除此之外,配置绑定还支持针对数据、集合和字典类型的绑定。

[507]绑定配置项的值

最简单配置绑定的莫过于针对配置树叶子节点配置节的绑定。这样的配置节承载着原子配置项的值,而且这个值是一个字符串,所以针对它的配置绑定最终体现为如何将这个字符串转换成指定的目标类型,这样的操作体现在IConfiguration接口如下两个GetValue扩展方法上。

public static class ConfigurationBinder
{public static T GetValue<T>(IConfiguration configuration, string sectionKey);public static T GetValue<T>(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)。
  • 如果目标类型不是Nullable<T>,那么针对目标类型的TypeConverter将被用来完成类型转换。
  • 如果目标类型为Nullable<T>,在原始值不是Null或者空字符串的情况下会直接返回Null,否则会按照上面的规则将值转换成类型基础T。

为了验证上述这些类型转化规则,我们编写了如下测试程序。如代码片段所示,我们利用注册的MemoryConfigurationSource添加了三个配置项,对应的值分别为Null、空字符串和“123”。在将IConfiguration对象构建出来后,我们调用它的GetValue<T>将三个值转换成Object、Int32和Nullable<Int32>类型。

using Microsoft.Extensions.Configuration;
using System.Diagnostics;var source = new Dictionary<string, string?>
{["foo"] = null,["bar"] = "",["baz"] = "123"
};var root = new ConfigurationBuilder().AddInMemoryCollection(source).Build();//针对object
Debug.Assert(root.GetValue<object>("foo") == null);
Debug.Assert("".Equals(root.GetValue<object>("bar")));
Debug.Assert("123".Equals(root.GetValue<object>("baz")));//针对普通类型
Debug.Assert(root.GetValue<int>("foo") == 0);
Debug.Assert(root.GetValue<int>("baz") == 123);//针对Nullable<T>
Debug.Assert(root.GetValue<int?>("foo") == null);
Debug.Assert(root.GetValue<int?>("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 Dictionary<string, string>
{["point"] = "(123,456)"
};var root = new ConfigurationBuilder().AddInMemoryCollection(source).Build();var point = root.GetValue<Point>("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所示的树来体现。

6-13

图1 复杂对象的配置树

如果需要通过配置的形式表示一个完整的Profile对象,只需要提供四个叶子节点(性别、年龄、电子邮箱地址和电话号码)对应的配置数据,配置字典只需要按照表1来存储这四个键值对就可以了。

表1 针对复杂对象的配置数据结构

Key

Value

Gender

Male

Age

18

ContactInfo:Email

foobar@outlook.com

ContactInfo:PhoneNo

123456789

我们通过下面的程序来验证针对复合数据类型的绑定。我们先创建一个ConfigurationBuilder对象,并利用注册的MemoryConfigurationSource对象添加了表5-2所示的配置数据。在构建出IConfiguration对象之后,我们调用它的Get<T>扩展方法将其绑定为Profile对象。

using App;
using Microsoft.Extensions.Configuration;
using System.Diagnostics;var source = new Dictionary<string, string>
{["gender"] = "Male",["age"]  = "18",["contactInfo:emailAddress"] = "foobar@outlook.com",["contactInfo:phoneNo"] = "123456789"
};var configuration = new ConfigurationBuilder().AddInMemoryCollection(source).Build();var profile = configuration.Get<Profile>();
Debug.Assert(profile.Gender == Gender.Male);
Debug.Assert(profile.Age == 18);
Debug.Assert(profile.ContactInfo.EmailAddress == "foobar@outlook.com");
Debug.Assert(profile.ContactInfo.PhoneNo == "123456789");

[510]集合的配置绑定

如果配置绑定的目标类型是一个集合(包括数组),那么当前IConfiguration对象的每个子配置节将绑定为集合的元素。如果目标类型为元素类型为Profile的集合,那么配置树应该具有图2所示的结构。既然能够正确地将集合对象通过一个合法的配置树体现出来,那么就可以将它转换成配置字典

6-14


图2 集合对象的配置树

我们利用如下的实例来演示针对集合的配置绑定。如代码片段所示,我们创建了一个ConfigurationBuilder对象,并为它注册了一个MemoryConfigurationSource对象,并利用注册的MemoryConfigurationSource对象添加了配置数据。在构建出IConfiguration对象之后,我们调用它的Get<T>扩展方法将它分别绑定为一个IList<Profile>和Profile数组对象。

using App;
using Microsoft.Extensions.Configuration;
using System.Diagnostics;var source = new Dictionary<string, string>
{["0:gender"] = "Male",["0:age"]  = "18",["0:contactInfo:emailAddress"] = "foo@outlook.com",["0:contactInfo:phoneNo"] = "123",["1:gender"]  = "Male",["1:age"] = "25",["1:contactInfo:emailAddress"] = "bar@outlook.com",["1:contactInfo:phoneNo"] = "456",["2:gender"]  = "Female",["2:age"] = "36",["2:contactInfo:emailAddress"] = "baz@outlook.com",["2:contactInfo:phoneNo"] = "789"
};var configuration = new ConfigurationBuilder().AddInMemoryCollection(source).Build();var list = configuration.Get<IList<Profile>>();
Debug.Assert(list[0].ContactInfo.EmailAddress == "foo@outlook.com");
Debug.Assert(list[1].ContactInfo.EmailAddress == "bar@outlook.com");
Debug.Assert(list[2].ContactInfo.EmailAddress == "baz@outlook.com");var array = configuration.Get<Profile[]>();
Debug.Assert(array[0].ContactInfo.EmailAddress == "foo@outlook.com");
Debug.Assert(array[1].ContactInfo.EmailAddress == "bar@outlook.com");
Debug.Assert(array[2].ContactInfo.EmailAddress == "baz@outlook.com");

[511]集合和数组的配置绑定的差异

针对集合的配置绑定不会因为某个元素的绑定失败而终止。如果目标类型是数组,最终绑定生成的数组长度与子配置节的个数总是一致的。如果目标类型是列表,将不会生成对应的元素。我们将上面演示程序做了稍许的修改,将第一个元素的性别从“Male”改为“男”,那么针对这个Profile元素绑定将会失败。如果将目标类型设置为IEnumerable<Profile>,那么最终生成的集合只有两个元素。倘若目标类型切换成Profile数组,数组的长度依然为3,但是第一个元素是空。

using App;
using Microsoft.Extensions.Configuration;
using System.Diagnostics;var source = new Dictionary<string, string>
{["0:gender"]  = "男",["0:age"]  = "18",["0:contactInfo:emailAddress"] = "foo@outlook.com",["0:contactInfo:phoneNo"] = "123",["1:gender"] = "Male",["1:age"] = "25",["1:contactInfo:emailAddress"] = "bar@outlook.com",["1:contactInfo:phoneNo"] = "456",["2:gender"] = "Female",["2:age"] = "36",["2:contactInfo:emailAddress"] = "baz@outlook.com",["2:contactInfo:phoneNo"] = "789"
};var configuration = new ConfigurationBuilder().AddInMemoryCollection(source).Build();var list = configuration.Get<IList<Profile>>();
Debug.Assert(list.Count == 2);
Debug.Assert(list[0].ContactInfo.EmailAddress == "bar@outlook.com");
Debug.Assert(list[1].ContactInfo.EmailAddress == "baz@outlook.com");var array = configuration.Get<Profile[]>();
Debug.Assert(array.Length == 3);
Debug.Assert(array[0] == default);
Debug.Assert(array[1].ContactInfo.EmailAddress == "bar@outlook.com");
Debug.Assert(array[2].ContactInfo.EmailAddress == "baz@outlook.com");

[512]字典的配置绑定

能够通过配置绑定生成的字典是一个实现了IDictionary<string,T>的类型,它Key必须是一个字符串(或者枚举)。如果采用配置树的形式表示这样一个字典对象,就会发现它与针对集合的配置树在结构上几乎是一样的,唯一的区别是集合元素的索引直接变成字典元素的Key。也就是说,图2所示的配置树同样可以表示成一个具有三个元素的Dictionary<string, Profile>对象,它们对应的Key分别“0”、“1”和“2”,所以我们可以按照如下方式将承载相同结构数据的IConfiguration对象绑定为一个IDictionary<string, Profile >对象。如代码片段所示,我们将表示集合索引的整数(“0”、“1”和“2”)改成普通的字符串(“foo”、“bar”和“baz”)。

using App;
using Microsoft.Extensions.Configuration;
using System.Diagnostics;var source = new Dictionary<string, string>
{["foo:gender"] = "Male",["foo:age"] = "18",["foo:contactInfo:emailAddress"] = "foo@outlook.com",["foo:contactInfo:phoneNo"] = "123",["bar:gender"] = "Male",["bar:age"] = "25",["bar:contactInfo:emailAddress"] = "bar@outlook.com",["bar:contactInfo:phoneNo"] = "456",["baz:gender"] = "Female",["baz:age"] = "36",["baz:contactInfo:emailAddress"] = "baz@outlook.com",["baz:contactInfo:phoneNo"] = "789"
};var profiles = new ConfigurationBuilder().AddInMemoryCollection(source).Build().Get<IDictionary<string,Profile>>();;Debug.Assert(profiles["foo"].ContactInfo.EmailAddress == "foo@outlook.com");
Debug.Assert(profiles["bar"].ContactInfo.EmailAddress == "bar@outlook.com");
Debug.Assert(profiles["baz"].ContactInfo.EmailAddress == "baz@outlook.com");

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/867198.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【音视频 | RTSP】RTSP协议详解 及 抓包例子解析(详细而不赘述)

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…

华为开发者大会2024纪要:鸿蒙OS的全新篇章与AI大模型的革命

华为开发者大会2024纪要:鸿蒙OS的全新篇章与AI大模型的革命 在科技的浪潮中,华为再次引领潮流,2024年的开发者大会带来了一系列令人瞩目的创新成果。从鸿蒙操作系统的全新Beta版到盘古大模型的震撼发布,华为正以前所未有的速度重塑智能生态。以下是本次大会的亮点,让我们…

MUNIK解读ISO26262--系统架构

功能安全之系统阶段-系统架构 我们来浅析下功能安全系统阶段重要话题——“系统架构” 目录概览&#xff1a; 系统架构的作用系统架构类型系统架构层级的相关安全机制梳理 1.系统架构的作用 架构的思维包括抽象思维、分层思维、结构化思维和演化思维。通过将复杂系统分解…

哨兵1SAR空间数据包协议数据单元文档(七)

《哨兵1SAR空间数据包协议数据单元》文档对数据包的结构进行了详细描述&#xff0c;并提供了用户数据的格式和解码算法。 原文链接: 哨兵1SAR空间数据包协议数据单元文档英文版 同系列中的其他文章篇链接: 哨兵1SAR空间数据包协议数据单元文档&#xff08;一&#xff09; 哨兵…

lodash-es 基本使用

中文文档&#xff1a;https://www.lodashjs.com/ cloneDeep方法文档&#xff1a;https://www.lodashjs.com/docs/lodash.cloneDeep#_clonedeepvalue 参考掘金文章&#xff1a;https://juejin.cn/post/7354940462061715497 安装&#xff1a; pnpm install lodash-esnpm地址&a…

Javase-异常

文章目录 1. 异常概述2. 异常的继承结构3. 自定义异常4. 异常的处理5. 异常的使用6. finally语句块7. 方法覆盖与异常 1. 异常概述 什么是异常 ①什么是异常?有什么用? 1.Java中的异常是指程序运行时出现了错误或异常情况&#xff0c;导致程序无法继续正常执行的现象。例如&…

谷粒商城 - 树形菜单递归流查询、三级分类数据查询性能优化、Jmter 性能压测

目录 树形分类菜单&#xff08;递归查询&#xff0c;强扩展&#xff09; 1&#xff09;需求 2&#xff09;数据库表设计 3&#xff09;实现 4&#xff09;关于 asSequence 优化 性能压测 1&#xff09;Jmeter 安装使用说明 2&#xff09;中间件对性能的影响 三级分类数…

【Kubernetes】Pod 资源调度之亲和性调度

Pod 资源调度之亲和性调度 1.Node 亲和性调度1.1 Node 硬亲和性1.2 Node 软亲和性 2.Pod 亲和性调度2.1 Pod 硬亲和2.2 Pod 软亲和2.3 Pod 反亲和 Kubernetes 的 默认调度器 以 预选、优选、选定机制 完成将每个新的 Pod 资源绑定至为其选出的目标节点上&#xff0c;不过&#…

吴恩达深度学习笔记:机器学习策略(2)(ML Strategy (2)) 2.7-2.8

目录 第三门课 结构化机器学习项目&#xff08;Structuring Machine Learning Projects&#xff09;第二周&#xff1a;机器学习策略&#xff08;2&#xff09;(ML Strategy (2))2.7 迁移学习&#xff08;Transfer learning&#xff09; 第三门课 结构化机器学习项目&#xff0…

学习笔记——动态路由——IS-IS中间系统到中间系统(区域划分)

三、IS-IS区域划分 根据IS-IS路由器邻居关系&#xff0c;可以将IS-IS划分为两个区域——骨干区域和非骨干区域。&#xff08;注意&#xff0c;这里的区域不是上文中提到的Area ID&#xff09;由L2的IS-IS邻居构成的区域为骨干区域&#xff0c;由L1的IS-IS邻居构成的区域为非骨…

智能运维场景探索 | 运营分析

【本场景来源于 擎创科技《一体化数智运维AIOps解决方案》白皮书&#xff0c;经过重新编写】 该场景主要围绕生产运行、运营决策两个维度进行展开&#xff0c;通过对配置、性能、业务等运行数据的加工计算&#xff0c;形成可量化运营效果、可衡量发展方向的运营数据。整体以低…

基于Qt实现的PDF阅读、编辑工具

记录一下实现pdf工具功能 语言&#xff1a;c、qt IDE&#xff1a;vs2017 环境&#xff1a;win10 一、功能演示&#xff1a; 二、功能介绍&#xff1a; 1.基于saribbon主体界面框架&#xff0c;该框架主要是为了实现类似word导航项 2.加载PDF放大缩小以及预览功能 3.pdf页面跳转…

Python基础小知识问答系列-高效遍历多个不同类型元素的迭代器

1. 问题&#xff1a; 当需要对多个迭代器进行相同遍历操作时&#xff0c;如何避免因为迭代器之间的类型或者迭代器元素 数量过大引发的问题&#xff1f; 2. 解决方法&#xff1a; 使用itertools模块中的chain函数。 示例&#xff1a; from itertools import chainlist_a [2,…

matlab 抛物线图像绘制

抛物线图像绘制 x^2y4绘制结果 x^2y4 clc,clear,close all; length10; % 创建一个范围内的 x 和 y 值 x linspace(-length, length, 1000); y linspace(-length, length, 1000);% 创建一个网格来表示 x 和 y 值的组合 [X, Y] meshgrid(x, y);% 计算方程的左边和右边的值 LH…

QWidget成员函数功能和使用详细说明(四)(文字+用例+代码+效果图)

文章目录 1.测试工程配置2.成员函数2.1 void setParent(QWidget *parent)2.2 void setMouseTracking(bool enable)2.3 bool hasMouseTracking() const2.4 void setPalette(const QPalette &)2.5 const QPalette &palette() const2.6 int QWidget::grabShortcut(const Q…

实战干货,企业在数字化转型中如何通过最佳实践落地BI报表?

引言&#xff1a;上一篇文章我们提到&#xff1a;通过9大步骤&#xff0c;帮助企业在数字化转型中搭建数据分析的报表体系&#xff01;在实际中的落地过程&#xff0c;通过实施服务的哪些最佳实践可以确保落地效果&#xff0c;达到项目预期目标&#xff0c;给客户带来实质价值&…

香蕉云编+uniapp打包ios的开发包和生产包

登录香蕉云编&#xff0c;找到 云编-ios证书生成&#xff0c;新建CSR文件&#xff0c;并下载csr文件。 登录苹果开发者中心&#xff0c;进入证书页面。 1.创建一个证书&#xff0c;选择ios Distribution类型即可&#xff0c;这是个通用的证书&#xff0c;既能用来打正式包又能…

“郭有才”商标主要类别都已被注册!

前阵山东网红“郭有才”火遍大江北&#xff0c;当然少不了许多想去申请注册“郭有才”商标名称的&#xff0c;普推商标知产老杨检索&#xff0c;发现“郭有才”商标申请了43个类别&#xff0c;基本上类别都被申请注册&#xff0c;已注册的商标大多是在“郭有才”火之前申请注册…

MyBatis入门程序详解

目录 一、MyBatis概述 二、编写MyBatis入门程序 三、配置SQL提示 四、传统jdbc的劣势 一、MyBatis概述 MyBatis是一个基于Java的持久层框架&#xff0c;它内部封装了JDBC操作&#xff0c;使得开发人员可以更专注于SQL语句本身而非繁琐的JDBC操作细节。在MyBatis中&#xff0…

最新全平台无人直播硬改XCMS系统,支持任何平台

软件功能: 改虚拟摄像头为真实摄像头&#xff0c;改真实麦克风&#xff0c;图层去重、镜头晃动、增加噪点去重、随机播放辅音&#xff0c;两条音轨帮助音频去重、随机音效、随机播放速度&#xff0c;直播源实时转播等等.防违规&#xff0c;防非实时 设备需求: 电脑&#xf…