【.net深呼吸】动态类型(高级篇)
前面老周给大家介绍了动态类型使用的娱乐级别用法,其实,在很多情景下,娱乐级别的用法已经满足需求了。
如果,你想自己来控制动态类型的行为和数据的存取,那么,就可以考虑用今天所说的高大上技术了。比如,你希望自己弄个字典来存取数据,又或者,你不想用字典,你想用XML来存取数据,那么就必须自己来实现动态对象的行为了。
实现的原理就是从DynamicObject类(位于System.Dynamic命名空间)派生出你自己的类。注意看,这个类的构造函数是protected的,也就是你无法把它实例化,所以,你要从该类派生,来实现你自己的动态行为。
实现方法是重写该类的虚方法,不一定要全部重写(你也不可能全部重写,个别方法不支持VB和C#),最常用的是实现以下三个方法:
TrySetMember:当向对象的动态属性赋值时用到。
TryGetMember:有set的,自然就有get的,所以当要获取属性值时重写。
TryInvokeMember:当要调用动态的方法时重写。
动态对象的成员是在运行阶段来解析的,所以名字是不确定的,这三个方法的第一个参数是一个binder,先不管它是什么类型的binder,因为不同的成员其binder不同。比如,属性调用是GetMemberBinder,不管是get还是set,都是这个;如果是方法调用则为InvokeMemberBinder。不管是啥binder,它的Name属性可以返回成员的名字。
例如,obj.Size = 0.55f,那么实现时,binder的Name属性就返回"Size"。
理论太抽象了,给大伙来点干货吧。下面这个类,我实现了属性的get和set行为,以及方法调用行为。这个自定义的动态类型,我依然是使用Dictionary<string, object>字典来存取数据。
public sealed class MyDynamicObject : DynamicObject
{
#region 私有字段
Dictionary<string, object> dic = null;
#endregion #region 构造方法
public MyDynamicObject()
{
dic = new Dictionary<string, object>();
}
#endregion #region 重写的方法
/// <summary>
/// 设置成员的值,如属性。
/// </summary>
/// <param name="binder"></param>
/// <param name="value"></param>
/// <returns></returns>
public override bool TrySetMember(SetMemberBinder binder, object value)
{
// binder.Name属性表示设置的成员名字,
// 比如动态对象变量k,k.Age = 22,则binder.Name为"Age",
// 此处把它转化为小写字母,作为字典的Key来存储
dic[binder.Name.ToLower()] = value;
/*
如果操作成功,返回true;
如果操作不成功,返回false。
此处直接操作字典数据,基本不会发生错误,
所以直接返回true。
*/
return true;
} /// <summary>
/// 获取成员的值,如属性等。
/// </summary>
/// <param name="binder"></param>
/// <param name="result"></param>
/// <returns></returns>
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
string key = binder.Name.ToLower();
if (dic.ContainsKey(key))
{
result = dic[key];
return true;
}
result = null;
return false;
} /// <summary>
/// 方法调用实现
/// </summary>
/// <param name="binder"></param>
/// <param name="args"></param>
/// <param name="result"></param>
/// <returns></returns>
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
result = 0d;
// 如果参数个数不是1个,则调用失败
if (args.Length != ) return false;
// 如果参数类型不能隐式转化为double,则调用失败
object a = args[];
if (a == null) return false;
if ((typeof(double).IsAssignableFrom(a.GetType())) == false) return false;
// 判断方法名称
string methodName = binder.Name.ToLower();
double num = Convert.ToDouble(a);
if (methodName == "m2")
{
result = Math.Pow(num, 2d); //二次方
}
else if (methodName == "m3")
{
result = Math.Pow(num, 3d); //三次方
}
return true;
}
#endregion
}
代码好像有点长,但是,你别指望我会一行一行地给你解释,老周的教育理念就是:“非解释型教学”。这些方法都是返回布尔类型的,你认为调用成功就返回true,你要是认为调用方没资格调用或调用是错的,就返回false。至于说返回false会有什么后果,不要问我,你自己试试就知道了,不要向我问那些可以轻松通过实验验证的问题。
不过,哦,在实现方法调用的TryInvokeMember方法,我还是要说一下。首先,第一个参数binder就不说了,前面说过了,就是包含方法名字,返回类型等信息。第二个参数args是一个object数组,要是方法没有参数就是0个元素,要是有2个参数就是2个元素,注意参数是不固定的,都说了,动态对象是运行时才解析的,一切都是不确定的。最后的result参数是方法的返回值,out方向,所以在TryInvokeMember返回前你必须给它赋值。
在TryInvokeMember实现代码中,有这个表达式,可能大伙不是很熟,就这个:
typeof(double).IsAssignableFrom(a.GetType())
它的意思是参数中的类型的变量能不能赋值给当前类型的变量,比如本例,当前类型是double,用IsAssignableFrom来验证一下指定的type的变量能不能赋值给double类型的变量
如果a的类型为int,它是可以赋值给double类型的变量的。
好了,自定义的动态类型写好了,下面就用它来装装逼吧。
dynamic dobj = new MyDynamicObject();
// 成员赋值
dobj.Title = "好消息";
dobj.Content = "京东全场0.5折优惠。";
// 输出
Console.WriteLine($"标题:{dobj.Title}\n内容:{dobj.Content}"); // 调用方法
Console.WriteLine("10的平方 {0}", dobj.M2(10d));
Console.WriteLine("3的立方 {0}", dobj.M3(3d));
Title和Content属性都是随便命名的,因为编译阶段不检查,所以可以随便写,但是,你取值时用的名字必须要和赋值时的名字相同。同理,方法M1和M2也是随意写的名字。至于说能不能成功调用,就取决于你的自定义动态类型的处理逻辑了。
下面看看装逼的结果。

好了,高级篇就说完了。改天有空,老周再写超级篇,会给大伙儿演示一个更牛逼的自定义动态类型。
【.net深呼吸】动态类型(高级篇)的更多相关文章
- 玩转动态编译 - 高级篇:一,IL访问静态属性和字段
IL介绍 通用中间语言(Common Intermediate Language,简称CIL,发音为"sill"或"kill")是一种属于通用语言架构和.NET ...
- 玩转动态编译 - 高级篇:二,IL设置静态属性,字段和类型转换
静态属性赋值 先来看 Reflector反射出的IL源码(感谢Moen的提示),这次用 Release模式编译,去掉那些无用的辅助指令 public void AAA(string s) { MyCl ...
- Zabbix-绘制动态拓扑图高级篇
0.官网文档介绍: https://www.zabbix.com/documentation/4.0/manual/config/visualisation/maps/map 一.设备名字使用宏显示 ...
- 【.net深呼吸】动态类型(娱乐篇)
有朋友跟老周说,动态类型是干吗的,他不太熟悉,希望老周可以讲一讲.没事,这事情老周也比较TMD乐意做的,因为老周写的这些烂文本来就是为了普及基础知识的,坚定不移地为社会基础教育而服务. 首先,咱们要知 ...
- 【.NET深呼吸】动态类型(扩充篇)
前面两文中,老周已向大家介绍了关于动态类型对象的两种级别的使用方案,本篇呢,老周再讲一个自定义动态类型的例子. 前面给大家演示的例子中,动态类型中包装的是字典类型来存储数据的,这一次咱们换一种风味,老 ...
- Python 学习 第四篇:动态类型模型
Python的变量不用声明,赋值之后就可以直接使用,类型是在运行过程中自动确定的,这就是动态类型模型.该模型把变量和对象设计成两个不同的实体,对象是存储数据的地方,对象的类型是由初始值自动决定的,而变 ...
- 【转载】Spark性能优化指南——高级篇
前言 数据倾斜调优 调优概述 数据倾斜发生时的现象 数据倾斜发生的原理 如何定位导致数据倾斜的代码 查看导致数据倾斜的key的数据分布情况 数据倾斜的解决方案 解决方案一:使用Hive ETL预处理数 ...
- ORM查询语言(OQL)简介--高级篇(续):庐山真貌
相关文章内容索引: ORM查询语言(OQL)简介--概念篇 ORM查询语言(OQL)简介--实例篇 ORM查询语言(OQL)简介--高级篇:脱胎换骨 ORM查询语言(OQL)简介--高级篇(续):庐山 ...
- 【转】【技术博客】Spark性能优化指南——高级篇
http://mp.weixin.qq.com/s?__biz=MjM5NjQ5MTI5OA==&mid=2651745207&idx=1&sn=3d70d59cede236e ...
随机推荐
- Swift与C#的基础语法比较
背景: 这两天不小心看了一下Swift的基础语法,感觉既然看了,还是写一下笔记,留个痕迹~ 总体而言,感觉Swift是一种前后端多种语言混合的产物~~~ 做为一名.NET阵营人士,少少多多总喜欢通过对 ...
- CSS十问——好奇心+刨根问底=CSSer
最近有时间,想把酝酿的几篇博客都写出来,今天前端小学生带着10个问题,跟大家分享一下学习CSS的一些体会,我觉得想学好CSS,必须保持一颗好奇心和刨根问底的劲头,而不是复制粘贴,得过且过.本人能力有限 ...
- C语言 · Torry的困惑(基本型)
问题描述 Torry从小喜爱数学.一天,老师告诉他,像2.3.5.7--这样的数叫做质数.Torry突然想到一个问题,前10.100.1000.10000--个质数的乘积是多少呢?他把这个问题告诉老师 ...
- Spring框架概述
Spring是最流行的Java企业级应用开发框架,全球数以百万的开发者在使用Spring框架创建高性能.易测试.可重用的代码. Spring框架的核心特性可以应用于任何Java应用,但扩展的JavaE ...
- Javascript实用方法二
承接上一篇, Object keys object的keys方法能够获取一个给定对象的所有键(key/属性名)并以数组的形式返回.这个方法可以用于键的筛选.匹配等. var basket = { st ...
- nginx源码分析之模块初始化
在nginx启动过程中,模块的初始化是整个启动过程中的重要部分,而且了解了模块初始化的过程对应后面具体分析各个模块会有事半功倍的效果.在我看来,分析源码来了解模块的初始化是最直接不过的了,所以下面主要 ...
- Shell碎碎念
1. 字符串如何大小写转换 str="This is a Bash Shell script." 1> tr方式 newstr=`tr '[A-Z]' '[a-z]' < ...
- DDD 领域驱动设计-商品建模之路
最近在做电商业务中,有关商品业务改版的一些东西,后端的架构设计采用现在很流行的微服务,有关微服务的简单概念: 微服务是一种架构风格,一个大型复杂软件应用由一个或多个微服务组成.系统中的各个微服务可被独 ...
- Ajax实现原理,代码封装
都知道实现页面的异步操作需要使用Ajax,那么Ajax到是怎么实现异步操作的呢? 首先需要认识一个对象 --> XMLHttpRequest 对象 --> Ajax的核心.它有许多的属性和 ...
- BPM合同管理解决方案分享
一.方案概述合同是组织与组织间所订协议的法律 表现形式,体现着双方对于合作在法律和道德上的承诺.然而,大多数企业的合同管理都或多或少存在合同审批过程不规范.签订草率.审批权责不清.合同执行跟踪难.合同 ...