今天看了博客园里面的dynamic用法,我犹豫从来没接触过,今天恶补了一下,把我对dynamic的认识分享了出来,大家一起学习。

Visual C# 2010 引入了一个新类型 dynamic。

该类型是一种静态类型,但类型为 dynamic 的对象会跳过静态类型检查。

大多数情况下,该对象就像具有类型 object 一样。 在编译时,将假定类型化为 dynamic 的元素支持任何操作。

为什么会有这个类呢,我们可以看一下js的代码来判断为什么会需要这个类

window.onload = function () {

var person1 = new Object();

person1.SayHi= function () { alert("我Sayhi方法"); }

var person2 = new Object();

IsMetheod(person1);//我是SayHi方法

IsMetheod(person2);//没有此方法

}

function IsMetheod(obj)

{

if (obj && typeof obj.SayHi === "function") {

return obj.SayHi();

}

else {

alert("没有此方法");

return null;

}

}

通过js代码我们可以去直接在对象上添加属性,而且还可以在使用属性之前去判断该属性或者方法是否存在。如果想要这样做,我们可以直接去操作dynamic对象去操作。

首先我们应先了解到一个接口,虽然dynamic可以像object类一样标识大部分类,但是如果想要用到像下面的例子一样动态的为对象绑定属性,必须实现IDynamicMetaObjectProvider这个接口。(这个接口我们先看完这个例子再说)

dynamic dy = new ExpandoObject();

dy.name = ".NET";

dy.age = 5;

Console.WriteLine(dy.name+":"+dy.age);//".NET:5"

大家可能看到了我们new的不是dynamic,对的,应为dynamic是一个静态的类型,所以我们是没有办法去new的,那怎样得到呢,这就提到了IDynamicMetaObjectProvider这个接口了,至于这个接口有什么用,微软官网上是这么说的"表示一个动态对象,在运行时可将该对象的操作进行绑定。"这也就是说,我们在程序编译之后运行的时候,把给对象绑定的方法动态的加载进去,所以,我们为dynamic对象绑定属性的时候,编译是能通过的,只是在运行的时候会出错。

这个接口里面只有一个方法GetMetaObject(),这个方法的作用是返回 DynamicMetaObject,它负责绑定对此对象执行的操作。所以只要实现了这个接口,我们就可以对实现该接口的类执行动态绑定操作。上例中也正是因为ExpanoObject实现了这个接口,可以通过new 这个类来演示动态绑定对象的方法。

但是如果把这些动态绑定的属性直接加在了dynamic上面,肯定不合适。这就需要将这个功能给扩展出来,刚才提到了,只要实现了那个接口就可以实现数据的动态绑定,可能不是很准确。在实际中也不会说只会去实现那个接口就能完成属性的动态添加。幸运的是.c#已经给出了一个接口去供我们继承,只要我们使用的类继承了DynamicObject这个类,我们可以通过重写里面的一些方法来扩展属性。下图是C#定义的DynamicObject

好了,说了这么多铺垫,我们来真正看一下比较简单的应用吧,我们以前写c#代码是不能通过js去那样写的的,让我们来看看通过dynamic我们是否可以完成这样的写法呢?

注意:下面的方法都是DynamicObject定义的,我们重写就好了,不必纠结为什么这样,看完再说。

public class Mydynamic:DynamicObject

{

//转杯一个数据字典,去保存我们属性和属性值

Dictionary<string, object> dic = new Dictionary<string, object>();

public override IEnumerable<string> GetDynamicMemberNames()

{

return dic.Keys;

}

//设置值的属性

public override bool TrySetMember(SetMemberBinder binder, object value)

{

dic[binder.Name] = value;

return true;

}

//得到值

public override bool TryGetMember(GetMemberBinder binder, out object result)

{

dic.TryGetValue(binder.Name,out result);

return true;

}

class Program

{

static void Main(string[] args)

{

dynamic dy = new Mydynamic();

dy.Name = "小白";

dy.age = 15;

Console.WriteLine(dy.Name+":"+dy.age);//"小白:15"

Console.ReadKey();

}

}

看到了吧,我们通过继承的DynamicObject这个类同样可以实现对对象属性的动态添加,不过要注意这里面的两个方法,就是TryGetMenber和TryGetMember这两个方法,没错这两个方法就是为为动态属性赋值和取值的,此外还有很多删除、通过下标得到属性等方法。设置值和取值的方法给我们了,我们如果想对获取的值进行业务的处理,在这里完全可以做得到。我们还是来现分析一下,这个主程序是怎么工作的,当dy.Name的时候,先从该类的集合字典里面去找,如果找到这个属性,为其赋值或者修改,如果没有找到,则添加到数据字典里。在运行的时候,绑定到这个对象上,该对象就有了该属性了。

我们再看一下一个判断业务的例子吧,

假定您需要一种数据结构来存储数字的文本和数值表达式,并且您希望定义此数据结构到字符串和整数的转换。

下面的代码示例演示如何实现从 DynamicObject 类派生的 DynamicNumber 类。 DynamicNumber 重写 TryConvert 方法来启用类型转换。 它还会覆盖 TrySetMember 和TryGetMember 方法以允许访问数据元素。

在此示例中,仅支持到字符串和整数的转换。 如果试图将对象转换为任何其他类型,将引发运行时异常。

public class Demo_dynymic:System.Dynamic.DynamicObject

{

Dictionary<string, object> dictionary

= new Dictionary<string, object>();

public override bool TryGetMember(

GetMemberBinder binder, out object result)

{

return dictionary.TryGetValue(binder.Name, out result);

}

public override bool TrySetMember(

SetMemberBinder binder, object value)

{

dictionary[binder.Name] = value;

return true;

}

//这个方法是用类型转换的。

public override bool TryConvert(

ConvertBinder binder, out object result)

{

if (binder.Type == typeof(String))

{

result = dictionary["Txt"];

return true;

}

if (binder.Type == typeof(int))

{

result = dictionary["Num"];

return true;

}

return base.TryConvert(binder, out result);

}

}

class Program

{

static void Main(string[] args)

{

dynamic dy = new Demo_dynymic();

dy.Txt = "哈哈哈";

dy.Num = 1;

int num = dy;//会启用TryConvert

string txt = dy;//会启用TryConvert

Console.WriteLine(num+txt);//1哈哈哈

Console.ReadKey();

}

}

我们再来看看里面的TryInvoke这个方法的用法吧。

TryInvoke从 DynamicObject 类派生的类可以重写此方法,以指定如何为动态对象执行调用对象的操作。 未重写此方法时,语言的运行时联编程序确定该行为。(大多数情况下,将引发运行时异常。)

如果此方法被重写,当您执行运算(如 sampleObject(100))时自动调用此方法,其中 sampleObject 从 DynamicObject 类派生。说简单点,就是我们可以通过重写这个方法,使用函数的形式来改变类对象的行为,也就是说我们通过函数形式来操作该类的属性。举个例子。

我们不想通过类名.属性的方式来添加属性,我们可以改写TryInvoke方法来完成通过函数参数形式赋值。具体看代码。

public override bool TryInvoke(

InvokeBinder binder, object[] args, out object result)

{

//有两个参数,而且第一个参数是整型,第二个是字符型。

//因为我们通过这种形式赋值,所以在用的时候,数据类型一定要一致。

if ((args.Length == 2) &&

(args[0].GetType() == typeof(int)) &&

(args[1].GetType() == typeof(String)))

{

if (dictionary.ContainsKey("Num"))

dictionary["Num"] = args[0];

else

dictionary.Add("Num", args[0]);

if (dictionary.ContainsKey("Txt"))

dictionary["Txt"] = args[1];

else

dictionary.Add("Txt", args[1]);

result = true;

return true;

}

else

{

result = false;

return false;

}

}

class Program

{

static void Main(string[] args)

{

dynamic dy = new Demo_dynymic();

//通过方法对属性赋值

dy(1, "one");

//因为属性名在后台我们已经确定了,所以访问的时候要写出来

//注意:.不出来,因为编译的时候,属性还不存在,只有运行的时候,才存在

Console.WriteLine(dy.Txt+dy.Num);//one1

Console.ReadKey();

}

}

还有很多方法,我就不一一例举了,总之要实现对对象的动态属性添加,有几个步骤

1. 子类里面包含一个私有变量,用于存储数据. 这暂且叫做Data;

2.TryGetMember(GetMemberBinder binder, out object result) 方法实现对数据的获取. binder.Name就是需要获取的属性的名称,result 是获取的属性值. 通过binder.Name在Data中获取到对应的属性值,传出到外面.(注意到了吧result是out参数)

3.TrySetMember(SetMemberBinder binder, object value) 对存在的属性进行赋值. 上面的Set方法中,我都判断了binder.Name在data里面是否存在。如果不存在就无法赋值。返回false,如果外面对不存在的属性复制那么将会报错.。

参考:http://www.cnblogs.com/FourLeafCloverZc/p/4348722.html

https://msdn.microsoft.com/zh-cn/library/system.dynamic.dynamicobject(v=vs.110).aspx

浅谈dynamic的简单使用用法的更多相关文章

  1. 浅谈Dynamic 关键字系列之一:dynamic 就是Object(转)

    C# 4.0提供了一个dynamic 关键字,那么什么是dynamic,究竟dynamic是如何工作的呢? 从最简单的示例开始: static void Main(string[] args) { d ...

  2. 浅谈Invoke 和 BegionInvoke的用法

    很多人对Invoke和BeginInvoke理解不深刻,不知道该怎么应用,在这篇博文里将详细阐述Invoke和BeginInvoke的用法: 首先说下Invoke和BeginInvoke有两种用法: ...

  3. 浅谈JS中 reduce() 的用法

    过去有很长一段时间,我一直很难理解 reduce() 这个方法的具体用法,平时也很少用到它.事实上,如果你能真正了解它的话,其实在很多地方我们都可以用得上,那么今天我们就来简单聊聊JS中 reduce ...

  4. VC++ 浅谈VS2010中CMFCToolBar的用法

    本文将给大家介绍Visual Studio 2010中CMFCToolBar的用法,CMFCToolBar可以让用户自定义工具栏图标,使用静态成员函数SetUserImages()将一个CMFCToo ...

  5. 浅谈Dynamic 关键字系列之三(上):ExpandoObject, DynamicObject, DynamicMetaObject

    http://www.cnblogs.com/LoveJenny/archive/2011/07/05/2098578.html ExpandoObject:表示一个对象,该对象包含可在运行时动态添加 ...

  6. 浅谈移动端rem的用法

    一 什么是rem? “font size of the root element 这是w3c的定义 也就是说是相对于根节点(html节点)的字体大小的单位. 目前主流的浏览器基本都支持rem这个单位, ...

  7. 浅谈Sql各种join的用法

    1.left join.right join.inner join三者区别 left join(左联接) 返回包括左表中的所有记录和右表中联结字段相等的记录 right join(右联接) 返回包括右 ...

  8. 浅谈Spring框架注解的用法分析

    原文出处: locality 1.@Component是Spring定义的一个通用注解,可以注解任何bean. 2.@Scope定义bean的作用域,其默认作用域是”singleton”,除此之外还有 ...

  9. 由jtable浅谈vector<vector<Object>>的用法(转自a718515028的专栏)

    以前只用过vector<Object>  ,但是在做从数据库导出数据放到jtable中时,发现还有个vector<vector<Object>>的用法. 先说jta ...

随机推荐

  1. 在C++中调用DLL中的函数 (3)

    1.dll的优点 代码复用是提高软件开发效率的重要途径.一般而言,只要某部分代码具有通用性,就可将它构造成相对独立的功能模块并在之后的项目中重复使用.比较常见的例子是各种应用程序框架,ATL.MFC等 ...

  2. virtual box 中两个虚拟机 、宿主机 三机互通并且能上外网设置

    virtual box 中两个虚拟机 .宿主机 三机互通并且能上外网设置 1:背景:因为需要学习linux,所以需要在虚拟机里装linux系统,测试要么宿主机与虚拟机linux网络实验测试:要么另一台 ...

  3. leetcode 20

    判断括号的顺序是否正确: 思路:用一个堆栈来存储符号序列,按照符号匹配规则进行堆栈操作: 前括号一律入栈,后括号如果跟栈顶符号匹配,栈顶符号出栈如果,若不匹配则返回false: 最后栈为空返回true ...

  4. Easyui扩展或者重载(方法和属性)

    1: 使用$.fn.datagrid.defaults.editors重载默认值. 每个编辑器都有以下方法: 名称 属性 描述 init container, options 初始化编辑器并返回目标对 ...

  5. java Literals

    Primitive Data Types The Java programming language is statically-typed, which means that all variabl ...

  6. yii2.0 DetailView 自定义样式

    GII 生成如下: <?= DetailView::widget([ 'model' => $model, 'attributes' => [ 'id', ['label'=> ...

  7. 常规轮询请求,客户端用Ajax调webservice的方法

    服务端发布webservice,下图方框中的一定要有 客户端代码 <script type="text/javascript"> $(document).ready(f ...

  8. Win7下安装IEWebControls.msi

    编写人:CC阿爸 2014-2-22 IEWebControls.msi是发布在.net 1.1时代.微软为弥布.net控件的不足而发布一组控件.很多程序猿都喜欢用到他. 方法一: 首先保证IIS7安 ...

  9. php下intval()和(int)转换有哪些区别

    想知道使用intval()和(int)转换有什么区别? 或者说两者有什么不同,包括功能.定义方面的.或者和使用频率.效率等. 复制代码代码如下: <?php  echo "<br ...

  10. c#判断网络连接状态示例代码

    使用c#判断网络连接状态的代码. 代码: public partial class Form1 : Form { [DllImport() == true) { label1.Text = " ...