深入理解C#(第3版)-- 【C#4】第14章 静态语言中的动态绑定(学习笔记)
14.1 何谓、何时、为何、如何
14.1.1 何谓动态类型
编译器知道代码中表达式的类型,知道任何类型中可用的成员。它应用了相当复杂的规则来决定哪个成员应该在何时使用。这包括了重载决策;在(动态类型出现)之前的唯一途径是根据对象在执行时的类型,来选择虚方法的实现。决定使用哪个成员的过程称为绑定(binding),对于静态类型的语言来说,绑定发生在编译时。
而在动态类型的语言中,所有的绑定都发生在执行时。编译器或解析器可以检查语法是否正确,但却无法检查所调用的方法或所访问的属性是否真的存在。
14.1.2 动态类型什么时候有用,为什么
首先,如果你知道要调用的成员名称、要传入的参数以及要调用的对象.
动态类型的第二个重要的特性是,对象可以通过分析提供给它的名称和参数来响应某个调用。
14.1.3 C# 4如何提供动态类型
C# 4 引入了一个新的类型,称为dynamic。
事实上,dynamic并不代表一个特定的CLR 类型。它实际上只是包含System.Dynamic.DynamicAttribute特性的System.Object 。
14.2 关于动态的快速指南
几乎所有CLR 类型都可以隐式转换为dynamic。
所有dynamic类型的表达式都可以隐式转换为CLR 类型。
使用dynamic类型值的表达式通常会动态地求值。
动态求值表达式的静态类型通常被视为dynamic。
14.3 动态类型示例
Massive(https://github.com/robconery/massive)
Dapper(http://code.google.com/p/dapper-dot-net/)
Json.NET (http://json.codeplex.com)
14.3.1 COM和Office
14.3.2 动态语言
1. 为什么要在C#中使用IronPython
2. 入门:内嵌Hello, World
3. 用ScriptScope存储和获取信息
4. 综合应用
关于依赖注入和控制反转,可以参考Martin Fowler著名的文章 http://www.martinfowler.com/articles/injection.html
14.3.3 纯托管代码中的动态类型
1. 执行时类型推断
2. 弥补泛型操作符的不足
Summing a sequence dynamically
3. 鸭子类型
4. 多重分发
14.4 幕后原理
http://blogs.msdn.com/b/samng/
http://mng.bz/0M6A
14.4.1 DLR简介
Dynamic Language Runtime
http://mng.bz/0M6A
DLR 它真的仅仅只是一个库。尽管它同样以运行时为名,却与CLR (Common Language Runtime ,公共语言运行时)不在同一个级别——它不涉及JIT编译、本地API封送(marshal)、垃圾回收等内容。

http://dlr.codeplex.com
http://mono-project.com
14.4.2 DLR核心概念
1. 调用点
2. 接收器和绑定器
3. 规则和缓存
14.4.3 C#编译器如何处理动态
1. 如果使用了动态,那么它就是动态的
代码清单14-16 方法重载和动态值
static void Execute(string x) { Console.WriteLine("String overload"); } static void Execute(dynamic x) { Console.WriteLine("Dynamic overload"); } ... dynamic text = "text"; Execute(text); //打印"String Overload" dynamic number = 10; Execute(number); //打印"Dynamic Overload"
2. 它是动态的……除非例外情况
3. CLR类型与动态类型之间的转换
4. 动态表达式并不总是动态地求值
5. 动态求值的表达式并不总是动态类型
6. 创建调用点和绑定器
14.4.4 更加智能的C#编译器
1. 在执行时保存编译器行为
代码清单14-18 单个类型中的动态重载决策
static void Execute(dynamic x, string y) { Console.WriteLine("dynamic, string"); } static void Execute(dynamic x, object y) { Console.WriteLine("dynamic, object"); } ... object text = "text"; dynamic d = 10; Execute(d, text); //打印"dynamic, object"
代码清单14-19 类层次结构中的动态重载决策
class Base { public void Execute(object x) { Console.WriteLine("object"); } } class Derived : Base { public void Execute(string x) { Console.WriteLine("string"); } } ... Base receiver = new Derived(); dynamic d = "text"; receiver.Execute(d); //打印"object"
2. 动态代码的编译时错误
14.4.5 动态代码的约束
1. 不能动态处理扩展方法
这不仅意味着不能调用动态值的扩展方法,还意味着不能将动态值作为参数传入扩展方法。编译器推荐了两种变通方案。如果你知道使用哪个重载,可以在方法内将动态值转换为正确的类型。或者,假设你知道扩展方法所在的静态类型,可以像调用普通的静态方法那样进行调用。
2. 委托与动态类型之间转换的限制
3. 构造函数和静态方法
4. 类型声明和泛型类型参数
你不能声明一个基类为dynamic的类型。你同样不能将dynamic用于类型参数的约束,或作为类型所实现的接口的一部分。你可以将其用于基类的类型实参,或在声明变量时将其用于接口。
例如,下面的声明是无效的:
class BaseTypeOfDynamic:dynamic
class DynamicTypeConstraint<T>where T:dynamic
class DynamicTypeConstraint<T>where T:List<dynamic>
class DynamicInterface:IEnumerable<dynamic>
而以下声明则有效:
class GenericDynamicBaseClass:List<dynamic>
IEnumerable<dynamic> variable;
14.5 实现动态行为
14.5.1 使用ExpandoObject
1. 设置或获取单独的属性
2. 创建DOM树
14.5.2 使用DynamicObject
1. 准备工作
2. DynamicObject 支持的简单成员
3. 覆盖TryXXX 方法
4. 覆盖GetDynamicMemberNames
14.5.3 实现IDynamicMetaObjectProvider
代码清单14-35 不含元对象代码的Rumplelstiltskin 类型
public sealed class Rumpelstiltskin : IDynamicMetaObjectProvider { private readonly string name; public Rumpelstiltskin(string name) { this.name = name; } public DynamicMetaObject GetMetaObject(Expression expression) { return new MetaRumpelstiltskin(expression, this); } private object RespondToWrongGuess(string guess) { Console.WriteLine("No, I'm not {0}! (I'm {1}.)", guess, name); return false; } private object RespondToRightGuess() { Console.WriteLine("Curses! Foiled again!"); return true; } }
这两个方法为什么返回object ?
你可能会奇怪,为什么这两个方法返回 object 而不是bool呢?实际上,我一开始实现的是void方法,但不幸的是动态方法调用必须有返回值,并且就我的经验来看,绑定器总是希望能返回object。(可以检查ReturnType 属性。)在执行时调用void方法将抛出异常,bool方法也是如此;我们需要自行装箱,使类型能够匹配。我们可以将装箱构建在表达式中,但修改方法的返回类型要简单得多。
浙公网安备 33010602011771号