C#中的动态类型(Dynamic)
一、动态类型简介
.NET 4 中引入了动态类型。动态对象(dynamicObject
)使您可以处理诸如 JSON 文档之类的结构内容,这些结构的组成可能要到运行时才能知道【 该类型是一种静态类型,但类型为 dynamic
的对象会跳过静态类型检查。 大多数情况下,该对象就像具有类型 object
一样。 在编译时,将假定类型化为 dynamic
的元素支持任何操作。 因此,不必考虑对象是从 COM API、从动态语言(例如 IronPython)、从 HTML 文档对象模型 (DOM)、从反射还是从程序中的其他位置获取自己的值。 但是,如果代码无效,则在运行时会捕获到错误。】
.NET 4.0 中引入的 dynamic
关键字为 C# 编程带来了一个范式转变。对于 C# 程序员来说,强类型系统之上的动态行为可能会让人感到不适 —— 当您在编译过程中失去类型安全性时,这似乎是一种倒退。【动态编程可能使您面临运行时错误。声明一个在执行过程中会发生变化的动态变量是可怕的,当开发人员对数据做出错误的假设时,代码质量就会受到影响】。
对 C# 程序员来说,避免代码中的动态行为是合乎逻辑的,具有强类型的经典方法有很多好处。通过类型检查得到的数据类型的良好反馈对于正常运行的程序是至关重要的,一个好的类型系统可以更好地表达意图并减少代码中的歧义。
随着动态语言运行时(Dynamic Language Runtime,DLR)的引入,这对 C# 意味着什么呢? .NET 提供了丰富的类型系统,可用于编写企业级软件。让我们来仔细看看 dynamic
关键字,并探索一下它的功能。
二、类型层次结构
C#中的动态类型(Dynamic)的项目工程https://download.csdn.net/download/xiaochenXIHUA/82343997 公共语言运行时(Common Language Runtime,CLR)中的每种类型都继自 System.Object
,【这意味着 object
类型是整个类型系统的公共父类】。当我们研究更神奇的动态行为时,这一事实本身就能为我们提供帮助。这里的想法是开发这种“代码感”,以便于您了解如何驾驭 C# 中的动态类型。
C#的基础数据类型继承自ValueType;而ValueType
重写来自 object
类的默认行为。ValueType
的子类在栈(stack)上运行,它们的生命周期较短,效率更高。而string则是派生自object。
以下为演示程序:
//1-基础类型 是否继承 ValueTypeprivate static void BaseTypeInheritValueType<T>(){string str = $"{typeof(T).Name}\t继承于 ValueType:{typeof(T).IsSubclassOf(typeof(ValueType))}";Print(str);}//2-ValueType 是否继承 System.Objectprivate static void ValueTypeInheritObject(){string str = $"ValueType 继承于 System.Object:{typeof(ValueType).IsSubclassOf(typeof(System.Object))}";Print(str);}//3-string 是否继承 System.Objectprivate static void StringInheritObject(){string str = $"string 继承于 System.Object:{typeof(string).IsSubclassOf(typeof(System.Object))}";Print(str);}
//1-byte 是否继承 ValueTypeBaseTypeInheritValueType<byte>();//1-short 是否继承 ValueTypeBaseTypeInheritValueType<short>();//1-int 是否继承 ValueTypeBaseTypeInheritValueType<int>();//2-uint 是否继承 ValueTypeBaseTypeInheritValueType<uint>();//1-Long 是否继承 ValueTypeBaseTypeInheritValueType<long>();//1-float 是否继承 ValueTypeBaseTypeInheritValueType<float>();//1-double 是否继承 ValueTypeBaseTypeInheritValueType<double>();//1-bool 是否继承 ValueTypeBaseTypeInheritValueType<bool>();//1-Enum 是否继承 ValueTypeBaseTypeInheritValueType<Enum>();//1-char 是否继承 ValueTypeBaseTypeInheritValueType<char>();//1-string 是否继承 ValueTypeBaseTypeInheritValueType<string>();
值类型和引用类型都是 CLR 的基本构建块,这种优雅的类型系统在 .NET 4.0 和动态类型之前就有了。如下是公共语言运行时(CLR) 的类型系统:
三、动态语言运行时
3.1、动态语言运行时基础
动态语言运行时(Dynamic Language Runtime, DLR)是处理动态对象的一种便捷方法。比如:您有 XML 或 JSON 格式的数据,但是数据其中的成员你并不知道。此时DLR 允许您使用自然代码来处理对象和访问成员。
对于 C#,这使您可以处理在编译时不知道其类型的库。动态类型消除了自然 API 代码中的万能字符串。这就开启了像 IronPython 一样位于 CLR 之上的动态语言。
可以将 DLR 视为支持三项主要服务:
序号 | 内容 | 说明 |
1 | 表达式树 | 表达式树,来自 System.Linq.Expressions 命名空间。编译器在运行时生成具有动态语言互操作性的表达式树 |
2 | 调用站点缓存 |
调用站点缓存,即缓存动态操作的结果。DLR 缓存像 a + b 之类的操作,并存储 a 和 b 的特征。当执行动态操作时,DLR 将检索先前操作中可用的信息。
|
3 | 动态对象互操作性是可用于访问 DLR 的 C# 类型 |
动态对象互操作性是可用于访问 DLR 的 C# 类型。这些类型包括 DynamicObject 和 ExpandoObject 。可用的类型还有很多
|
DLR 和 CLR 的结合图如下:
每种类型都是从 System.Object
派生而来的。嗯,这句话对于 CLR 是适用的,但是对于 DLR 呢?
示例代码如下:
//4-测试DLR 是否继承 System.Objectprivate static void DLRObjectInheritObject<T>(){string str = $"{typeof(T).Name}\t继承于 System.Object:{typeof(T).IsSubclassOf(typeof(System.Object))}";Print(str);}
//4-测试DynamicObject 是否继承 System.ObjectDLRObjectInheritObject<System.Dynamic.DynamicObject>();//4-测试ExpandoObject 是否继承 System.ObjectDLRObjectInheritObject<System.Dynamic.ExpandoObject>();
运行结果如下:
3.2、动态语言运行时应用场景
动态类型解决的一个问题是,当您有一个不知道其成员的 JSON HTTP 请求时,假设要在 C# 中使用此任意的 JSON。要解决这个问题,请将此 JSON 序列化为 C# 动态类型。
我将使用 Newtonsoft 序列化库,您可以通过 NuGet 添加此依赖项。
您可以使用这个序列化程序来处理 ExpandoObject
和 DynamicObject
。探索每种动态类型给动态编程带来了什么。
3.3、ExpandoObject 动态类型
【ExpandoObject
】
是一种方便的类型,允许设置和检索动态成员。它实现了 IDynamicMetaObjectProvider
,该接口允许在 DLR 中的语言之间共享实例。因为它实现了 IDictionary
和 IEnumerable
,所以它也可以处理 CLR 中的类型。
举例来说,它允许将 ExpandoObject
的实例转换为 IDictionary
,然后像其它任意的 IDictionary
类型一样枚举成员。
要用 ExpandoObject
处理任意 JSON,您可以编写以下程序:
using System;
using System.Collections.Generic;
using System.Text;namespace Test_Dynamic
{class PeopleInfo{public string Id { get; set; }public string Name { get; set; }public string Sex { get; set; }public int Age { get; set; }public string TelNumber { get; set; }public string Address { get; set; }}//Class_end}
//获取人员信息private static PeopleInfo GetPeopleInfo(){PeopleInfo peopleInfo = new PeopleInfo();peopleInfo.Id = Guid.NewGuid().ToString("N");peopleInfo.Name = "牛奶咖啡";peopleInfo.Sex = "男";peopleInfo.Age = 27;peopleInfo.TelNumber = "13115672345";peopleInfo.Address = "中华人民共和国测试省测试市测试街道测试号";return peopleInfo;}//将一个对象序列化为Json字符串private static string GetJsonStrOfObject<T>(T t){string str = Newtonsoft.Json.JsonConvert.SerializeObject(t);return str;}//将一个Json字符串反序列化为动态类型(通过ExpandoObject类型)private static dynamic GetExpandoObjectResultOfJsonStr(string jsonStr){if (string.IsNullOrEmpty(jsonStr)) return null;dynamic result = Newtonsoft.Json.JsonConvert.DeserializeObject<System.Dynamic.ExpandoObject>(jsonStr);return result;}//输出ExpandoObject类型的解析内容private static void PrintExpandoObjectInfo(dynamic dc){string str = $"编号:{dc?.Id}\t姓名:{dc?.Name}\t性别:{dc?.Sex}\t年龄:{dc?.Age}\t" +$"电话:{dc?.TelNumber}\t住址:{dc?.Address}";Print(str);}//输出ExpandoObject类型的解析内容(IDictionary)private static void PrintExpandoObjectInfo2(dynamic dc){if (dc == null) return;foreach (var item in dc as System.Collections.Generic.IDictionary<string, object>??new System.Collections.Generic.Dictionary<string, object>()){string str=$"IDictionary={item.Key}:{item.Value}"; Print(str);}}
调用方法示例如下:
//5-ExpandoObject示例private static void ExpandoObjectSample(){//1-将一个PeopleInfo对象序列化为Json字符串string jsonStr = GetJsonStrOfObject(GetPeopleInfo());//2-将一个Json字符串反序列化为动态类型(通过ExpandoObject类型)dynamic dc = GetExpandoObjectResultOfJsonStr(jsonStr);//3-输出ExpandoObject类型的解析内容PrintExpandoObjectInfo(dc);//4-输出ExpandoObject类型的解析内容(IDictionary)PrintExpandoObjectInfo2(dc);}
运行结果如下:
请注意:尽管它是一个动态 JSON,但它会绑定到 CLR 中的 C# 类型。由于数字的类型未知,因此序列化程序默认会选择支持的最大类型(比如Age字段就使用的是long类型)。
我们成功地将序列化结果转换成了具有 null 检查的 dynamic
类型,其原因是序列化程序返回来自 CLR的 object
类型。因为 ExpandoObject
继承自 System.Object
,所以可以被拆箱成 DLR 类型。
更奇妙的是,可以用 IDictionary
枚举 dynamic,如下图所示:
//输出ExpandoObject类型的解析内容(IDictionary)private static void PrintExpandoObjectInfo2(dynamic dc){if (dc == null) return;foreach (var item in dc as System.Collections.Generic.IDictionary<string, object>??new System.Collections.Generic.Dictionary<string, object>()){string str=$"IDictionary={item.Key}:{item.Value}"; Print(str);}}
3.4、DynamicObject 动态类型
【DynamicObject】
提供对动态类型的精确控制。您可以继承该类型并重写动态行为。例如:您可以定义如何设置和获取类型中的动态成员。DynamicObject
允许您通过重写选择实现哪些动态操作。这比实现 IDynamicMetaObjectProvider
的语言实现方式更易访问。它是一个抽象类,需要继承它而不是实例化它。该类有 14 个虚方法,它们定义了类型的动态操作,每个虚方法都允许重写以指定动态行为。
假设您想要精确控制动态 JSON 中的内容。尽管事先不知道其属性,您却可以使用 DynamicObject
来控制类型。
让我们来重写三个方法,TryGetMember
、TrySetMember
和 GetDynamicMemberNames
:
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Text;namespace Test_Dynamic
{class OpcJsonOfDynamic<T>: System.Dynamic.DynamicObject{private readonly IDictionary<string, T> _objProperty;public OpcJsonOfDynamic(){_objProperty = new Dictionary<string,T>();}public override bool TryGetMember(GetMemberBinder binder, out object result){T typeObj;if (_objProperty.TryGetValue(binder.Name,out typeObj)){result = typeObj;return true;}result = null;return false;}public override bool TrySetMember(SetMemberBinder binder, object value){if (value.GetType()!=typeof(T)){return false;}_objProperty[binder.Name]=(T)value;return true;}public override IEnumerable<string> GetDynamicMemberNames(){return _objProperty.Keys;}public IDictionary<string, T> GetKeyValues(){return _objProperty;}}//Class_end}
C# 泛型强类型 _objProperty
以泛型的方式驱动成员类型。这意味着其属性类型来自泛型类型 T
。动态 JSON 成员位于字典中,并且仅存储泛型类型。此动态类型允许同一类型的同类成员集合。尽管它允许动态成员集,但您可以强类型其行为。假设您只关心任意 JSON 中的 string
类型:
//获取人员信息private static PeopleInfo GetPeopleInfo(){PeopleInfo peopleInfo = new PeopleInfo();peopleInfo.Id = Guid.NewGuid().ToString("N");peopleInfo.Name = "牛奶咖啡";peopleInfo.Sex = "男";peopleInfo.Age = 27;peopleInfo.TelNumber = "13115672345";peopleInfo.Address = "中华人民共和国测试省测试市测试街道测试号";return peopleInfo;}//输出DynamicObject类型的内容private static void PrintDynamicObjectInfo(System.Dynamic.DynamicObject dc){if (dc == null) return;if (dc is OpcJsonOfDynamic<string>){OpcJsonOfDynamic<string> opcJsonOfDynamic = (dc as OpcJsonOfDynamic<string>);foreach (var item in opcJsonOfDynamic.GetKeyValues()){string str = $"键:{item.Key}\t值:{item.Value}";Print(str);}}}
调用方法示例如下:
//6-DynamicObject示例private static void DynamicObjectSample(){//1-将一个PeopleInfo对象序列化为Json字符串string jsonStr = GetJsonStrOfObject(GetPeopleInfo());//2-通过Dynamic对象操作JsonSystem.Dynamic.DynamicObject dcObj = Newtonsoft.Json.JsonConvert.DeserializeObject<OpcJsonOfDynamic<string>>(jsonStr);//3-输出dcObj内容PrintDynamicObjectInfo(dcObj);}
运行结果如下:
3.5、类型结果
- CLR 和 DLR 中的所有类型都继承自
System.Object
- DLR 是所有动态操作发生的地方
ExpandoObject
实现了 CLR 中诸如IDictionary
的可枚举类型DynamicObject
通过虚方法对动态类型进行精确控制
四、参考文档
Working with the Dynamic Type in C# - Simple Talk (red-gate.com)https://www.red-gate.com/simple-talk/development/dotnet-development/working-with-the-dynamic-type-in-c/使用类型 dynamic - C# 编程指南 | Microsoft Docshttps://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/types/using-type-dynamic
C#中的动态类型(Dynamic)相关推荐
- C#中动态类型dynamic用法浅析
动态类型dynamic是微软在.net framework 4.0开始引入的,其目的是在程序编译过程中忽略对类型的检查,等到运行时刻再明确定义的对象的类型. 使用dynamic类型可以简化代码 ...
- var和dynamic的应用 var、动态类型 dynamic 深入浅析C#中的var和dynamic ----demo
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
- C++工作笔记- C++中的动态类型与动态绑定、虚函数、运行时多态的实现
动态类型与静态类型 静态类型 是指不需要考虑表达式的执行期语义,仅分析程序文本而决定的表达式类型.静态类型仅依赖于包含表达式的程序文本的形式,而在程序运行时不会改变.通俗的讲,就是上下文无关,在编译时 ...
- Python学习笔记整理(三)Python中的动态类型简介
Python中只有一个赋值模型 一.缺少类型声明语句的情况 在Python中,类型是在运行过程中自动决定的,而不是通过代码声明.这意味着没有必要事声明变量.只要记住,这个概念实质上对变量,对象和它们之 ...
- 使用 var 关键字在 Java 中使用动态类型
在本文中,我们将讨论 Java 10 的一项很酷的特性--在 Java 中引入 var 关键字 . 扫码关注<Java学研大本营>,加入读者群,分享更多精彩 Java 获得了 var 关键 ...
- python动态类型的坑_在Python中避免动态类型错误的策略是什么(NoneType没有属性x)?...
forgetting to check a type 这没什么意义.你很少需要"检查"一个类型.你只需运行单元测试,如果你提供了错误的类型对象,事情就会失败.根据我的经验,你不需要 ...
- 动态类型var和dynamic和传统确定类型区别和效率
伴随着vs2010的出现,c#4.0的诞生,与之而来的动态类型dynamic更是给net程序员们锦上添花,为自己的程序书写上带来了给大的便利.可到底怎么用,好不好用,效率这么样,也许是大家最迫切关注的 ...
- [.NET] 《Effective C#》快速笔记 - C# 中的动态编程
<Effective C#>快速笔记 - C# 中的动态编程 静态类型和动态类型各有所长,静态类型能够让编译器帮你找出更多的错误,因为编译器能够在编译时进行大部分的检查工作.C# 是一种静 ...
- [C#基础知识系列]专题十七:深入理解动态类型
本专题概要: 动态类型介绍 为什么需要动态类型 动态类型的使用 动态类型背后的故事 动态类型的约束 实现动态行为 总结 引言: 终于迎来了我们C# 4中特性了,C# 4主要有两方面的改善--Com 互 ...
- Python进阶09 动态类型
作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 谢谢TeaEra, 猫咪cat 动态类型(dynamic typing)是Pyth ...
最新文章
- 二、通过工厂方法来配置bean
- 在Eclipse中写第一个hibernate小例子
- 【转】自旋锁及其衍生锁
- linux的shell脚本语法与C语言不同之一
- matlab二项式拟合,数据回归分析和拟合的Matlab实现
- linux 嵌入式串口通信设计目的,基于linux的嵌入式串口通信.doc
- 为什么要选择基于NAS存储方案
- opensource项目_最佳Opensource.com:科学
- exploring spring
- 判断对象是否超出屏幕
- 【转】Using hash_map on GCC
- x-bov16 firmware android,MSD0431XX 松下
- 神经网络加速器设计研究:GoSPA ISCA2021论文研读
- 计算机体系结构量化研究方法——学习(一)
- wifi ap6212驱动移植及调试分析技术笔记
- 哈工大计算机保研面试专业课问题,[转载]哈工大保研面试
- 什么是5G聚合路由器?
- 基于GIS技术的公路路线方案决策支持系统开发初探
- 【日语五十音图快速记忆法】(看了这个,真的很好记)
- mandatory和immediate
热门文章
- python三重积分_(整理)三重积分及其计算和多重积分.
- JQuery和javascript优秀插件收集
- B站小甲鱼Python基础学习课堂笔记
- 手机+测试网络+苹果手机软件,iOS-用手机网络测试Ipv6
- Java项目:问卷调查系统(java+SSM+layui+JSP+Mysql)
- codeforces 407C Curious Array
- python输出星号等腰三角形_Python 打印矩形、直角三角形、等腰三角形、菱形
- 《进击的虫师》爬取豆瓣电影海报Top250(2020年10月23日更新)
- 基于UML的公开招聘教师管理系统建模的研究和设计
- Flutter:文件与网络操作摘要