C#学习笔记(十一):动态类型

C#是一门静态类型的语言,但是在C#4.0时微软引入了动态类型的概念。

dynamic

关键字dynamic用来定义动态对象,我们来看一下动态类型的一些特性。

调用不同类的相同方法

我们有两个或多个不相关的类,然后运行时需要可以调用到相同名称的方法,如下:

 1 using System;
 2
 3 namespace Study
 4 {
 5     class Program
 6     {
 7         static void Main(string[] args)
 8         {
 9             dynamic obj = GetObject(0);
10             Console.WriteLine(obj.Talk());
11
12             Console.Read();
13         }
14
15         private static Object GetObject(int type)
16         {
17             switch (type)
18             {
19                 case 1:
20                     return new Dog();
21             }
22             return new Robot();
23         }
24     }
25
26     public class Dog
27     {
28         public string Talk()
29         {
30             return "Wang Wang!";
31         }
32     }
33
34     public class Robot
35     {
36         public string Talk()
37         {
38             return "I`m a Robot!";
39         }
40     }
41 }

我们的两个类没有继承也没有应用相同的接口,但是可以调用到相同的方法,使用GetObject(1)可以得到想要的结果。

这就是动态类型,在编译时不会对方法等进行判断,而是在运行时才进行处理,如果调用到不存在的方法才会报错。

C#编译器允许你通过dynamic对象调用任何方法,即使这个方法根本不存在,编译器也不会在编译的时候报编译错误。只有在运行的时候,它才会检查这个对象的实际类型,并检查在它上面Talk()是什么意思。动态类型将使得C#可以以更加统一而便利的形式表示下列对象:

  • 来自动态编程语言——如Python或Ruby——的对象;
  • 通过IDispatch访问的COM对象;
  • 通过反射访问的一般.NET类型;
  • 结构发生过变化的对象——如HTML DOM对象;

当我们得到一个动态类型的对象时,不管它是来自COM还是IronPython、HTML DOM还是反射,只需要对其进行操作即可,动态语言运行时(DLR)会帮我们指出针对特定的对象以及这些操作的具体意义。这将给我们的开发带来极大的灵活性,并且能够极大程度上地精简我们的代码。

动态类型使用注意

  1. 不能调用扩展方法;
  2. 委托与动态类型不能进行隐式转换;
  3. 不能调用构造函数和静态方法;
  4. 类不能继承dynamic、泛型参数不能使用dynamic和接口实现也不能使用dynamic;

实现动态行为

实现动态行为有3种方法,分别可以用在不同的场合。

使用ExpandoObject类

直接使用ExpandoObject类来实现动态行为,代码如下:

 1 using System;
 2 using System.Dynamic;
 3
 4 namespace Study
 5 {
 6     class Program
 7     {
 8         static void Main(string[] args)
 9         {
10             dynamic obj = new ExpandoObject();
11             //添加属性
12             obj.name = "Li Lei";
13             obj.age = 20;
14             //添加方法
15             obj.Add = (Func<int, int, int>) ((a, b) => a + b);
16
17             Console.WriteLine("Name: " + obj.name);
18             Console.WriteLine("Age: " + obj.age);
19             Console.WriteLine("Add: " + obj.Add(100, 123));
20
21             Console.Read();
22         }
23     }
24 }

输出如下:

1 Name: Li Lei
2 Age: 20
3 Add: 223

继承DynamicObject类

通过继承DynamicObject类也可以实现动态效果,示例如下:

 1 using System;
 2 using System.Dynamic;
 3
 4 namespace Study
 5 {
 6     class Program
 7     {
 8         static void Main(string[] args)
 9         {
10             dynamic obj = new MyClass();
11             obj.name = "Li Lei";
12             obj.age = 20;
13             obj.CallFunc();
14
15             Console.Read();
16         }
17     }
18
19     public class MyClass : DynamicObject
20     {
21         public override bool TrySetMember(SetMemberBinder binder, object value)
22         {
23             Console.WriteLine("设置" + binder.Name + "为" + value);
24             return true;
25         }
26
27         public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
28         {
29             Console.WriteLine("调用" + binder.Name + "方法");
30             result = null;
31             return true;
32         }
33     }
34 }

输出如下:

1 设置name为Li Lei
2 设置age为20
3 调用CallFunc方法

实现IDynamicMetaObjectProvider接口

如果已经继承了其它的类,则可以通过实现IDynamicMetaObjectProvider接口来实现动态行为,例子如下:

 1 using System;
 2 using System.Dynamic;
 3 using System.Linq.Expressions;
 4
 5 namespace Study
 6 {
 7     class Program
 8     {
 9         static void Main(string[] args)
10         {
11             dynamic obj = new MyClass();
12             obj.CallFunc();
13
14             Console.Read();
15         }
16     }
17
18     public class MyClass : IDynamicMetaObjectProvider
19     {
20         public DynamicMetaObject GetMetaObject(Expression parameter)
21         {
22             Console.WriteLine("获取元数据");
23             return new MetaDynamic(parameter, this);
24         }
25     }
26
27     public class MetaDynamic : DynamicMetaObject
28     {
29         public MetaDynamic(Expression expression, object value) : base(expression, BindingRestrictions.Empty, value)
30         {
31         }
32
33         public override DynamicMetaObject BindInvokeMember(InvokeMemberBinder binder, DynamicMetaObject[] args)
34         {
35             MyClass target = base.Value as MyClass;
36             Expression self = Expression.Convert(base.Expression, typeof (MyClass));
37             var restrictions = BindingRestrictions.GetInstanceRestriction(self, target);
38             Console.WriteLine("调用" + binder.Name + "方法");
39             return new DynamicMetaObject(self, restrictions);
40         }
41     }
42 }

输出如下:

1 获取元数据
2 调用CallFunc方法
时间: 2024-10-25 10:15:10

C#学习笔记(十一):动态类型的相关文章

第十七篇:实例分析(4)--初探WDDM驱动学习笔记(十一)

感觉有必要把 KMDDOD_INITIALIZATION_DATA 中的这些函数指针的意思解释一下, 以便进一步的深入代码. DxgkDdiAddDevice 前面已经说过, 这个函数的主要内容是,将BASIC_DISPLAY_DRIVER实例指针存在context中, 以便后期使用, 支持多实例. DxgkDdiStartDevice 取得设备信息, 往注册表中加入内容, 从POST设备中获取FRAME BUFFER以及相关信息(DxgkCbAcquirePostDisplayOwnershi

Web Service学习笔记:动态调用WebService

原文:Web Service学习笔记:动态调用WebService 多数时候我们通过 "添加 Web 引用..." 创建客户端代理类的方式调用WebService,但在某些情况下我们可能需要在程序运行期间动态调用一个未知的服务.在 .NET Framework 的 System.Web.Services.Description 命名空间中有我们需要的东西. 具体步骤: 1. 从目标 URL 下载 WSDL 数据. 2. 使用 ServiceDescription 创建和格式化 WSDL

《Hibernate学习笔记十一》:树状结构设计

<Hibernate学习笔记十一>:树状结构设计 这是马士兵老师讲解Hibernate的一个作业题,树状结构设计,这是一个比较典型的例子,因此有必要写篇博文记录下. 树状结构的设计,它是在同一个类中使用了多对一(ManyToOne)和一对多(OneToMany). 在完成这个题目我们应该按照如下的步骤进行: 1.先思考数据库的模型应该是什么样的?? 数据库中的模型应该如下:即存在id p_id 2.思考面向对象的模型,及如何来进行映射??? 根据数据库中表的特点,对象应该有id name;由于

初探swift语言的学习笔记十一(performSelector)

作者:fengsh998 原文地址:http://blog.csdn.net/fengsh998/article/details/35842441 转载请注明出处 如果觉得文章对你有所帮助,请通过留言或关注微信公众帐号fengsh998来支持我,谢谢! 在OC中使用好好的performSelector,但不知为什么在swift有意的被拿掉了.更有甚者连IMP, objc_msgSend也不能用了.虽然想不通为什么,但应该有他的道理.就不纠结了. 大家可能在OC中使用得更多的就是延时处理,及后台处

Swift学习笔记(二)参数类型

关于参数类型,在以前的编程过程中,很多时间都忽视了形参与实参的区别.通过这两天的学习,算是捡回了漏掉的知识. 在swift中,参数有形参和实参之分,形参即只能在函数内部调用的参数,默认是不能修改的,如果想要修改就需要在参数前添加var声明. 但这样的声明过后,仍旧不会改变实参的值,这样就要用到inout了,传递给inout的参数类型必须是var类型的,不能是let类型或者字面类型,(字面类型是在swift中常提的一个术语,个人认为就是赋值语句,也不能修改)而且在传递过程中,要用传值符号"&

C# in Depth Third Edition 学习笔记-- 可空类型

1. 没有值怎么办? 客户下了一份订单,有订货日期,但尚未发货,但没有发货日期,怎么表述发货日期? C#2以后使用可空类型. 2. 为什么值类型的变量不能是null? 引用类型变量,其值是一个引用,即一个非空引用值提供了访问一个对象 的途径,对于null来说,作为一个特殊值,意味着不引用任何对象.所有引用的默认值都为null,内存中表示全零. 值类型变量,其值是它本身的真实数据.null不是有效的值类型的值. 3. C#1 解决不存在可空值类型 魔值:DateTime,牺牲公元元年中的某个值Da

MySQL学习笔记之三 表类型

你能用的数据库引擎取决于MySQL在安装时候是如何被编译的.要添加一个新的引擎,就必须编译MySQL.仅仅为了添加一个特性而编译应用程序的想法对于Windows的开发人员来说可能有点小题大做,得不偿失,但是在Unix的世界里,这已经成为了标准.在缺省的情况下,MySQL支持三个引擎:ISAM.MyISAM和HEAP.另外两种类型InnoDB和Berkley(BDB),也常常可以使用. ISAM ISAM是一个定义明确且历经时间考验的数据表格管理方法,它在设计之初就考虑到数据库被查询的次数远远大于

初探swift语言的学习笔记(可选类型?和隐式可选类型!)

可选类型.隐式可选类型 其次swift还引入一个较有趣的初始值设置语法使用"?"操作符及"!"号操作符 如:"var optionalString: String? = "Hello" optionalString == nil var optionalName: String? = "John Appleseed" var greeting = "Hello!" if let name = op

Linux System Programming 学习笔记(十一) 时间

1. 内核提供三种不同的方式来记录时间: Wall time (or real time):actual time and date in the real world Process time:the time that a process spends executing on a processor 包括用户时间user time 和 系统时间system time Monotonic time:use the system's uptime (time since boot) for t

C#学习笔记二: C#类型详解

前言 这次分享的主要内容有五个, 分别是值类型和引用类型, 装箱与拆箱,常量与变量,运算符重载,static字段和static构造函数. 后期的分享会针对于C#2.0 3.0 4.0 等新特性进行. 再会有三篇博客  这个系列的就会结束了. 也算是自己对园子中@Learning Hard出版的<<C#学习笔记>>的一个总结了. 博客内容基本上都是白天抽空在公司写好的了, 但是由于公司内部网络不能登录博客园所以只能够夜晚拿回来修改,  写的不好或者不对的地方也请各位大神指出. 在下感