Mads Torgersen给大家展示了C#中dynamic关键字的更多详细信息以及它的一些具体用法并谈及在选用dynamic关键字之前一些最终被废弃的替代设计方案
C# 将通过新的元类型dynamic来添加对后期绑定的支持任何直接声明为这种类型的变量或者从函数中返回这种类型的值都将自动地视为后期绑定这类似于在Visual Basic中把变量声明为object不过它现在可以支持任何类型系统了不仅仅是CTS(通用类型规范)和COM
一个重要之处是这个特性的目标就是为了支持后期绑定以及更多地为了支持近来流行的动态绑定动态类型明显不是C#的一个特性【译者注意指C#是静态语言本来无需动态类型的】不过是为了支持动态绑定的一个后果
还要着重注意的一点是反射并不是一种很好的替代方案使用反射的问题在于需要处理各种各样的类型使用Reflection命名空间调用方法的方式和在ScriptObject上调用方法的方式并不相同尤其Ruby/Python方法这样的第三方方法
一种选择是用波形号作为动态操作的前缀可惜这种方式马上也变得难以使用尤其在你开始研究类型转换数组索引和数学操作符的地方
object d = GetDynamicObject(); string result = ~(string) d ~[ d~
Length ~
];
下一个曾考虑过的选择是动态上下文类似unsafe和unchecked上下文那样你能够标注任意的代码块为dynamic这种方式的问题在于它很难把静态和动态代码混合在一起这种方式书写的代码类似下面
dynamic {
//some dynamic code
static {
//some statically bound code
dynamic {
//some dynamic code in some static code
}
//some more statically bound code
}
//some more dynamic code
}
第三种方案是传播性的表达式由于表达式的动态本质将产生向上传播的问题
object d = GetDynamicObject();
string result = (string) d[ dynamic(d)Length ];
当然它们选择的语法也不够完美虽然可以让大家轻易地读懂代码但是没有任何东西来表明一个动态调用是在实际Call Site当中被创建出来的唯一看到的信息是这个变量在哪里声明的
dynamic d = GetDynamicObject();
string result = (string) d[dLength ];
选用这种设计的关键原因是代码未必真的不够安全进行动态调用本身就像之前抛出异常那样不过现在你不用编写所有臃肿易出错的反射逻辑了
另外一个曾考虑过的选择是用dynamic修饰符来代替元类型使用这种模式的代码如下所示开发人员能够早期绑定到Foo的方法上而不是在任何东西上进行后期绑定虽然这样可以在一些边界情况下提高性能不过它却增加了总体的复杂等级这样的复杂度是难以接受的
dynamic Foo d = GetDynamicFooObject();
每逢动态组件进入到表达式中整个表达式将可能成为动态的这包括
方法调用
程序调用
成员访问
操作符运用
索引访问
例外是相当显而易见的转换和构造器将返回给你静态上下文虽然转换能被DLR类型系统所重写但是DLR会把转换的结果指定为适当的类型