技术心得记录:深入了解Dynamic&DLR(一)

简介: 技术心得记录:深入了解Dynamic&DLR(一)

本文主要谈谈个人对DLR的认识和学习,希望能和大家一起探讨下。


主要内容:


DLR在面向服务设计的必要性


dynamic类型


DLR ScriptRuntime


DynamicObject & ExpandoObject


1.DLR在面向服务设计中的必要性


题外前因话:商业业务环境的变更总是伴随着技术的变革。近来面向服务编程SOA的兴起是一种必然,涉及以下几个因素:


其一商业经营需要及时快速的调整;


其二在快速调整的同时,无需额外的开销,无需重构代码,重新发布平台;


其三商业平台的扩展性和稳定性;


其四商业平台维护费用;


SOA在业务平台整体上进行布局整合,发布服务契约,数据契约等等,那么涉及细颗粒度的操作,比如说商场需要实时对销货策略进行变更。1.客户类别不同打折销售,2.节假日不同打折,3.不同的商品类别折扣不同,4.促销商品折扣,5.销售额满多少,折扣多少等等,我们需要以后对销售策略进行实时维护,能新增,删除,修改。在当前我们可能通过App.config文件设置不同参数值来满足我们的业务需求,或者通过dll反射的方式来选择不同销售策略。但这些能灵活配置的有限,无法满足日益增长复杂业务逻辑的变化。对此我们需要这些业务需求能够“动态加载,动态注入”,最好是脚本语言,不需要进行第二次编译,现有的Framework能够自动解析执行。


C#仍是一种静态的类型化语言,无法完美支持动态编程。而Ruby,Python,JavaScript等天生在动态编程方面有绝对的优势。如果能加载第三方动态语言,并且自身具备和这些动态语言相同的某些动态功能。DLR(Dynamic Language Runtime)是添加到CLR的一系列服务,具有动态运行功能,并且允许加载第三方动态语言脚本,如Ruby和Python。DLR体系结构图如下:


2.新的关键字dynamic


dynamic是支持动态编程新的关键字,用此关键字声明object,编译器不会检查其类型安全,认定其任何操作都是安全有效的,只有再运行时才会判断,如果有错误,则会抛出RuntimeBinderException异常。这里要提到的是var关键字,var的对象是延迟确定的,当编译成IL时,其类型已经确定,且类型不可在运行时更改。dynamic类型可以在运行时根据需要转换为另外的类型。下表中描述他们的区别:


Dynamic


Var


编译器检查


不会检查


会检查


类型安全


不安全抛出RuntimeBinderException


类型安全


类型确定


类型不确定,可多次转换(转换对象之间不必存在关系)


类型延迟确定,可按照继承关系进行转换


下面用代码来展示下dynamic类型转换过程。可惜的是MS未对dynamic对象的方法提供智能感知(实际上对象在运行才能确定,也无从提供其方法,数据信息),感觉回归到了C时代。


+ View Code?1234567891011121314151617181920212223242526272829class Program{ static void Main(string【】 args) { dynamic dyn; dyn = 10; Console.WriteLine(dyn.GetType()); Console.WriteLine(dyn); dyn = "a string object"; Console.WriteLine(dyn.GetType()); Console.WriteLine(dyn); dyn = new User { Nickname = "loong" }; Console.WriteLine(dyn.GetType()); Console.WriteLine(dyn.GetWelcomeMsg()); }} class User{ public string Nickname { get; set; } public string GetWelcomeMsg() { return string.Format("Welcome {0}!",this.Nickname); }}


dynamic对象的类型是在运行时才根据当前对象来进行判断的,并且可以多次变更。这段代码执行结果如下:


good!那这样我们是不是可以说dynamic是万能的呢,实际上由于其对象类型不确定,也决定了不支持扩展方法,匿名方法(包含lambda表达式)也不能用做动态方法调用的参数。其次延伸开来,LINQ也与动态code无缘了。因为大多LINQ都是扩展方法。


C#是一种静态、类型化的语言,那么又是如何实现动态对象和方法的呢。我们先来看静态类型和动态类型在IL中有和区别。如下代码


View Code


1 class Program


2 {


3 static void Main(string【】 args)


4 {


5 StaticUser staticUser = new StaticUser();


6 //DynamicUser dynamicUser = new DynamicUser();


7


8 Console.WriteLine(staticUser.Nickname);


9 //Console.WriteLine(dynamicUser.Nickname);


10


11 Console.ReadLine();


12 }


13 }


14


15 class StaticUser


16 {


17 public string Nickname = "Loong";


18 }


19


20 class DynamicUser


21 {


22 public dynamic Nickname = "Loong";


23 }


我们来看下IL:


动态类型属性声明是


.field public object Nickname


.custom instance void 【System.Core】System.Runtime.CompilerServices.DynamicAttribute::.ctor() = ( 01 00 00 00 )


而静态类型属性声明


.field public string Nickname


动态类型属性是有一个object来代替目前声明的对象,之后用了System.Runtime.CompilerServices.DynamicAttribute。进而动态构造对象。这就是两者之间的差别。


我们再来比较下静态类型和动态类型在方法中执行情况:


首先是静态类型, IL_0001行调用newobj构造函数,IL_0008行获取该属性的value, 然后下一行输出。


View Code


1 .method private hidebysig static void Main(string【】 args) cil managed


2 {


3 .entrypoint


4 // Code size 26 (0x1a)


5 .maxstack 1


6 .locals init (【0】 class Loong.Dynamic.StaticUser staticUser)


7 IL_0000: nop


8 IL_0001: newobj instance void Loong.Dynamic.StaticUser::.ctor()


9 IL_0006: stloc.0


10 IL_0007: ldloc.0


11 IL_0008: ldfld string Loong.Dynamic.StaticUser::Nickname


12 IL_000d: call void 【mscorlib】System.Console::WriteLine(string)


13 IL_0012: nop


14 IL_0013: call string 【mscorlib】System.Console::ReadLine()


15 IL_0018: pop


16 IL_0019: ret


17 } // end of method Program::Main


动态类型,通过Microsoft.CSharp.RuntimeBinder初始化Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo C#动态操作执行信息,RuntimeBinderException处理 C# 运行时联编程序中的动态绑定时发生的错误等等。


其中有两个重要的类System.Runtime.CompilerServices.CallSite和System.Runtime.CompilerServices.CallSiteBinder.CallSite主要在运行期间查找动态对象归属类型,个人认为会和系统默认类型匹配, 继而再和自定义类型匹配。也就是说会扫描该应用程序域manged heap,查找该type。以确保该type有需要的执行的属性、方法等等。这个过程是非常耗时耗能的,MS也给出解决方案,CallSite这个类会缓存查找到的type信息,从而避免了重复查找。当CallSite执行完查找任务后,找到对应的type就调用CallSiteBinder()方法,产生表达树(这点和linq类似),表示将要执行的操作。如果没有找到该Type,则会抛出RuntimeBinderException。


View Code


1 .method private hidebysig static void Main(string【】 args) cil managed


2 {


3 .entrypoint


4 // Code size 125 (0x7d)


5 .maxstack 8


6 .locals init (【0】 class Loong.Dynamic.DynamicUser dynamicUser,


7 【1】 class 【Microsoft.CSharp】Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo【】 CS$0$0000)


8 IL_0000: //代码效果参考:http://www.jhylw.com.cn/125129557.html

nop

9 IL_0001: newobj instance void Loong.Dynamic.DynamicUser::.ctor()


10 IL_0006: stloc.0


11 IL_0007: ldsfld class 【System.Core】System.Runtime.CompilerServices.CallSite1[span style="color: rgba(0, 0, 255, 1)">class 【mscorlib】System.Action3[span style="color: rgba(0, 0, 255, 1)">class 【System.Core】System.Runtime.CompilerServices.CallSite,class 【mscorlib】System.Type,object Loong.Dynamic.Program/'oSiteContainer0'::'pSite1'


12 IL_000c: brtrue.s IL_0051


13 IL_000e: ldc.i4 0x100


14 IL_0013: ldstr "WriteLine"


15 IL_0018: ldnull


16 IL_0019: ldtoken Loong.Dynamic.Program


17 IL_001e: call class 【mscorlib】System.Type 【mscorlib】System.Type::GetTypeFromHandle(valuetype 【mscorlib】System.RuntimeTypeHandle)


18 IL_0023: ldc.i4.2


19 IL_0024: newarr 【Microsoft.CSharp】Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo


20 IL_0029: stloc.1


21 IL_002a: ldloc.1


22 IL_002b: ldc.i4.0


23 IL_002c: ldc.i4.s 33


24 IL_002e: ldnull


25 IL_002f: call class 【Microsoft.CSharp】Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo 【Microsoft.CSharp】Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype 【Microsoft.CSharp】Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags,


26

相关文章
|
存储 XML 关系型数据库
深入理解MySQL中的BLOB和TEXT数据类型
【8月更文挑战第31天】
1590 0
|
数据采集 Web App开发 搜索推荐
项目配置之道:优化Scrapy参数提升爬虫效率
项目配置之道:优化Scrapy参数提升爬虫效率
|
文字识别 专有云 测试技术
印刷文字识别使用问题之如何识别银行回单
印刷文字识别产品,通常称为OCR(Optical Character Recognition)技术,是一种将图像中的印刷或手写文字转换为机器编码文本的过程。这项技术广泛应用于多个行业和场景中,显著提升文档处理、信息提取和数据录入的效率。以下是印刷文字识别产品的一些典型使用合集。
|
1天前
|
数据采集 人工智能 安全
|
10天前
|
云安全 监控 安全
|
2天前
|
自然语言处理 API
万相 Wan2.6 全新升级发布!人人都能当导演的时代来了
通义万相2.6全新升级,支持文生图、图生视频、文生视频,打造电影级创作体验。智能分镜、角色扮演、音画同步,让创意一键成片,大众也能轻松制作高质量短视频。
910 150
|
15天前
|
机器学习/深度学习 人工智能 自然语言处理
Z-Image:冲击体验上限的下一代图像生成模型
通义实验室推出全新文生图模型Z-Image,以6B参数实现“快、稳、轻、准”突破。Turbo版本仅需8步亚秒级生成,支持16GB显存设备,中英双语理解与文字渲染尤为出色,真实感和美学表现媲美国际顶尖模型,被誉为“最值得关注的开源生图模型之一”。
1646 8
|
6天前
|
人工智能 前端开发 文件存储
星哥带你玩飞牛NAS-12:开源笔记的进化之路,效率玩家的新选择
星哥带你玩转飞牛NAS,部署开源笔记TriliumNext!支持树状知识库、多端同步、AI摘要与代码高亮,数据自主可控,打造个人“第二大脑”。高效玩家的新选择,轻松搭建专属知识管理体系。
365 152
|
7天前
|
人工智能 自然语言处理 API
一句话生成拓扑图!AI+Draw.io 封神开源组合,工具让你的效率爆炸
一句话生成拓扑图!next-ai-draw-io 结合 AI 与 Draw.io,通过自然语言秒出架构图,支持私有部署、免费大模型接口,彻底解放生产力,绘图效率直接爆炸。
603 152