前言

该系列准备继续完善,一共108篇,持续更新。

正文

为什么有动态类型呢?

是因为很多东西天生就是动态类型的。

比如xml 和 json、cvs、数据库表,这些本来就是数据类型的。

在反射系列中提及到,为什么有发送呢? 是因为只有在运行的时候你才能知道他是什么类型。

同样的xml、json这些也是只有运行的时候才知道他有什么样的类型,当我们加载xml、json 映射成一个对象的时候,里面的属性也只有加载完后我们的程序才知道。

那这样就有一个问题啊,那就是加载的时候我们的程序才知道有这个属性,那么这种没法处理了吗?

这个时候人就介入了,比如json开发人员是知道有一个字段叫做fistname的,那么使用动态类型,可以是dynamicObj.fistname 这样获取就可以了。

动态获取属性的值,这似乎反射也可以做到啊。是的啊,当然反射可以做到,那有没有可能dynamic 就是反射获取字段值的语法糖呢?

这样就可以了:

static void Main(string[] args)
{
var type = typeof(String);
var chars = new char[] { '1','2','3','4','5','6'};
object x = Activator.CreateInstance(type, chars);
PropertyInfo property = type.GetProperty("Length");
var y = property.GetValue(x);
dynamic a = "123456";
var b = a.Length;
var c = "123456";
var d = c.Length;
Console.ReadKey();
}

我们来反编译看一下到底是怎么样的?

可以看到是这样的:

先看反射这块,反射这块好理解哈:

然后动态类型这块,其实原理还是反射了,先检查类型是否存在然后去调用。

那么看来呢,我好想也没有找到动态类型跳过检查这一块。

如果检查失败会报:runtime-binder.runtimebinderException。

反射和动态类型不同的是,反射是运行时候生成的检查,而动态类型是编译的时候生成的,这个根据上面应该好理解吧。

也就是说反射是可以跳过检查的,但是动态类型不行。

只是说一下,个人觉得其实也没什么关系。因为其实不怎么影响效率。该用动态类型就用动态类型,该用反射就用反射,两种的方向不一致。

通过上面il编译后的,我们发现根本就没有这个dynamic 这个东西,会编译成别的东西,起到了包装器的作用。

static void Main(string[] args)
{
dynamic a = "123456";
var t = a.GetType();
Console.WriteLine(t);
Console.ReadKey();
}

当我们去运行它的时候获取类型的时候:

这个a 本身还是system.string.

对il来说没有动态类型这个概念。

然后有一个值得注意的误区:

就是有些人认为使用了dynamic 认为不存在装箱和拆箱?

这是一个非常值得实验的问题。

internal class Program
{
static void Main(string[] args)
{
dynamic a = 1;
Console.WriteLine(a);
}
}

为什么会这样呢? 因为dynamic 继承obejct,实际上可以理解为object,int 到 object 自然存在装箱。

实际上dynamic 十分简化原理是这样的:

object a = "test";
var t = typeof(x);
callSite b = factory.create(t);
var reuslt = b.invoke(a, "param")

然后动态类型是不支持调用扩展方法的,这个反射也不支持。这个后面讲到扩展方法的本质的时候,就知道为什么不支持了。

动态类型的场景:

如果不使用动态类型是这样的:

static void Main(string[] args)
{
XElement person = XElement.Parse(@"<Person>
<FirstName>1</FirstName><LastName>2</LastName></Person>");
Console.WriteLine(person.Descendants("FirstName").FirstOrDefault().Value);
}

那么如果有了动态类型怎么写呢?

static void Main(string[] args)
{
//XElement person = XElement.Parse(@"<Person>
// <FirstName>1</FirstName><LastName>2</LastName></Person>");
//Console.WriteLine(person.Descendants("FirstName").FirstOrDefault().Value);
dynamic person = DynamicXml.Parse(@"<Person>
<FirstName>1</FirstName><LastName>2</LastName></Person>"); Console.WriteLine(person.FirstName);
}
} public class DynamicXml : DynamicObject
{
private XElement Element { get; set; } public DynamicXml(
XElement element)
{
Element = element;
} public static DynamicXml Parse(string text)
{
return new DynamicXml(XElement.Parse(text));
} public override bool TryGetMember(GetMemberBinder binder, out object result)
{
bool success = false;
result = null;
XElement firstDescendant = Element.Descendants(binder.Name).FirstOrDefault();
if (firstDescendant != null)
{
if (firstDescendant.Descendants().Any())
{
result = new DynamicXml(firstDescendant);
}
else
{
result = firstDescendant.Value;
} success = true;
} return success;
} public override bool TrySetMember(SetMemberBinder binder, object value)
{
bool success = false;
XElement firstDescendant = Element.Descendants(binder.Name).FirstOrDefault();
if (firstDescendant != null)
{
if (value.GetType() == typeof(XElement))
{
firstDescendant.ReplaceWith(value);
}
else
{
firstDescendant.Value = value.ToString();
} success = true;
} return success;
}
}

如果定义了自己的动态类型那么更加方便。

因为本来我们就要传递字符串的,如果字符串传递错误本来就会报错,封装成一个动态类,从工程的角度来说就是更加优雅了。

然后又一个问题,那就是本身如果我们的 DynamicXml 就有这个属性呢?是调用TryGetMember的还是调用我们自己的呢?

事实证明会调用自己的,而不走TryGetMember。

说明先进性反射,如果反射找不到,然后判断是否继承dynamicObject,如果继承那么就调用TryGetMember获取,如果失败就抛出异常。

该系列持续更新。

重学c#系列——动态类型[二十二]的更多相关文章

  1. 【D3.V3.js系列教程】--(十二)坐标尺度

    [D3.V3.js系列教程]--(十二)坐标尺度 1.多种类型的缩放尺度 Quantitative Scales Linear Scales Identity Scales Power Scales ...

  2. springboot源码解析-管中窥豹系列之BeanPostProcessor(十二)

    一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...

  3. 重学c#系列——字典(十一)

    前言 重学c#系列继续更新,简单看一下字典的源码. 看源码主要是解释一下江湖中的两个传言: 字典foreach 顺序是字典添加的顺序 字典删除元素后,字典顺序将会改变 正文 那么就从实例化开始看起,这 ...

  4. Web 前端开发精华文章推荐(HTML5、CSS3、jQuery)【系列二十二】

    <Web 前端开发精华文章推荐>2014年第一期(总第二十二期)和大家见面了.梦想天空博客关注 前端开发 技术,分享各类能够提升网站用户体验的优秀 jQuery 插件,展示前沿的 HTML ...

  5. Linux Shell系列教程之(十二)Shell until循环

    本文是Linux Shell系列教程的第(十二)篇,更多Linux Shell教程请看:Linux Shell系列教程 在上两篇文章Linux Shell系列教程之(十)Shell for循环和Lin ...

  6. Django 系列博客(十二)

    Django 系列博客(十二) 前言 本篇博客继续介绍 Django 中的查询,分别为聚合查询和分组查询,以及 F 和 Q 查询. 聚合查询 语法:aggregate(*args, **kwargs) ...

  7. SQL注入之Sqli-labs系列第二十一关(基于复杂性的cookie POST报错注入)和二十二关(基于双引号的cookie POST报错注入)

    开始挑战第二十一关(Cookie Injection- Error Based- complex - string) 和二十二关(Cookie Injection- Error Based- Doub ...

  8. JAVA基础知识总结:一到二十二全部总结

    >一: 一.软件开发的常识 1.什么是软件? 一系列按照特定顺序组织起来的计算机数据或者指令 常见的软件: 系统软件:Windows\Mac OS \Linux 应用软件:QQ,一系列的播放器( ...

  9. VMware vSphere 服务器虚拟化之二十二桌面虚拟化之创建View Composer链接克隆的虚拟桌面池

    VMware vSphere 服务器虚拟化之二十二桌面虚拟化之创建View Composer链接克隆的虚拟桌面池 在上一节我们创建了完整克隆的自动专有桌面池,在创建过程比较缓慢,这次我们将学习创建Vi ...

  10. FreeSql (二十二)Dto 映射查询

    适合喜欢使用 dto 的朋友,很多时候 entity 与 dto 属性名相同,属性数据又不完全一致. 有的人先查回所有字段数据,再使用 AutoMapper 映射. 我们的功能是先映射,再只查询映射好 ...

随机推荐

  1. PostgreSQL 大对象导出报错问题分析

    1.前言 在处理用户问题过程遇到一个问题.用户通过pg_dump导出 bytea 对象时,当行的大小超过 1G时,会报错: [v8r6c5b41@dbhost01 ~]$ sys_dump -t t1 ...

  2. KingbaseES blob 类型数据导入导出

    KingbaseES兼容了oracle的blob数据类型.通常是用来保存二进制形式的大数据,也可以用来保存其他类型的数据. 下面来验证一下各种数据存储在数据库中形式. 建表 create table ...

  3. spring native 初体验实现 小米控制美的空调

    目前关于 spring native 分享的文章还比较少 写这篇文章的主要目前是分享一下自己写的一个 小米控制美的空调 的程序 集成 spring native 过程中碰到的一些问题和解决方法 先放地 ...

  4. 【设计模式】Java设计模式 - 享元模式

    Java设计模式 - 享元模式 不断学习才是王道 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 原创作品,更多关注我CSDN: 一个有梦有戏的人 准备将博客园.CSDN一起记录分享自己 ...

  5. Java开发学习(三十四)----Maven私服(二)本地仓库访问私服配置与私服资源上传下载

    一.本地仓库访问私服配置 我们通过IDEA将开发的模块上传到私服,中间是要经过本地Maven的 本地Maven需要知道私服的访问地址以及私服访问的用户名和密码 私服中的仓库很多,Maven最终要把资源 ...

  6. Python-Django模板

    前面将hello world输出给浏览器,将数据与 视图 混合在一起,不符合 MVC思想. 模板就是一个文本,用来分离文档的表现形式和内容. 在templates目录下创建一个html模板 然后需要向 ...

  7. typora收费了,最后一个免费版提供下载

    typora收费了,在这里,博主提供最后一个免费版下载,地址如下,顺便把typora导入和导出word时需要的工具也一同提供.最看不惯免费用着别人的软件,还搞引流的垃圾网站和公众号.地址如下 http ...

  8. ProxySQL(4):多层配置系统

    文章转载自:https://www.cnblogs.com/f-ck-need-u/p/9280793.html ProxySQL中的库 使用ProxySQL的Admin管理接口连上ProxySQL, ...

  9. Elasticsearch: analyzer

    在今天的文章中,我们来进一步了解analyzer. analyzer执行将输入字符流分解为token的过程,它一般发生在两个场合: 在indexing的时候,也即在建立索引的时候 在searching ...

  10. Beats:Beats在Kibana中的集中管理

    我们可以通过在命令行中对我们的Beats进行管理,比如我们可以启动metric几个模块,我们可以通过如下的命令来执行: ./metricbeat modules enable apache mysql ...