1. dynamic简介
在之前的文章有简单的谈到dynamic,这里更深入的来谈一下一些更实际的应用场景。C# 4.0提供的新的关键字dynamic。对带有dyamic声明的变量的所有操作都将在运行时进行解析。换句话说,你可以对它调用任何方法,编译阶段不会报告任何错误。
例如这个方法
public static void DoSomethingDynamic(dynamic thing)
{
try
{
thing.Act();
}
catch (RuntimeBinderException)
{
Console.WriteLine("thing does not implement Act");
}
}
这里声明了一个dynamic类型的变量thing,并调用其方法Act(),编译器并不保证thing一定有Act()方法,反之,这点必须由程序员保证,否则在运行时会导致RuntimeBinderException.
Beta1的名称空间与CTP的不一样,dynamic的名称空间现在位于System.Dynamic里,一些Class的名称也发生了变化。
2. 细说dynamic的魔术。
dynamic基本是编译器的魔术(因此可以预见Java可能很快也会跟进这一特性)。编译器会生成一个带urgly name的内部site container,这个site container带有一系列CallSite的泛型静态实例,这些实例是根据dynamic类型的变量、调用参数、返回值等生成的。
例如
dynamic b = "hello,ray";
int i= b.Length;
int j = a.Length;
编译器会生成4个有奇怪名字的静态实例(很奇怪,为什么不是优化成2个静态实例? )
private static class <Main>o__SiteContainer
{
// Fields
public static CallSite<Func<CallSite, object, int>> <>p__Site1;
public static CallSite<Func<CallSite, object, object>> <>p__Site2;
public static CallSite<Func<CallSite, object, int>> <>p__Site3;
public static CallSite<Func<CallSite, object, object>> <>p__Site4;
}
例子中CallSite<Func<CallSite, object, object>> 用于动态调用Length属性并返回object类型的结果,CallSite<Func<CallSite, object, int>> 将object类型的结果造型成我们希望int。
CallSite类有两个重要的属性:一个是Binder(类型为CallSiteBinder),另一个是Target(类型为T)。类型T通常是一个为Func或者Action的委托,Func与Action的区别就是Func返回值而Action不返回值,Func或Action的类型参数是由编译器生成的。
CallSite本身是个工厂类,用Create<T>(CalllSiteBinder binder)方法来创建实例,binder变量被简单地赋给了Binder属性,而Target属性,则通过调用MakeUpdateDelegate方法封装了System.Dynamic.UpdateDelegates的某个UpdateAndExecute方法。
UpdateDelegates的UpdateAndExecute方法命名有一定规律,有返回值的命名为UpdateAndExecute#,没有返回值的则是UpdateAndExecuteVoid#, "#"处为参数的个数,依次从0递增到10。
在MakuUpdateDelegate方法中,通过T的返回类型与调用参数的个数组合,Target属性最终被映射到UpdateDelegates的对应方法上。
在例子中的Target应该映射到UpdateDelegates的UpdateAndExecute0方法,该方法形式如下:
internal static TRet UpdateAndExecute0<TRet>(CallSite site)
{
..............非完整代码............
while (true)
{
site2.Target = target;
func = site2.Target = site2.Binder.BindDelegate<Func<CallSite, TRet>>(site2, args);
try
{
local = func.Invoke(site);
if (CallSiteOps.GetMatch(site))
{
return local;
}
}
...............非完整代码..............
}
--------------------- 以下为暂存草稿 有错误和纰漏----------------------
dynamic GetTuple()
{
return new { FirstName = “John”, LastName = “Adams” };
}
dynamic myTuple = GetTuple();
Console.WriteLine (myTuple.FirstName);
dynamic的实现是基于IDynamicObject接口和DynamicObject抽象类。而动态方法、属性的调用都被转为了TryGetMember、TryInvoke等方法的调用,各个方法对应的调用如下说明
public abstract class DynamicObject : IDynamicObject
{
//读属性时被调用
public virtual object TryGetMember(GetMemberBinder info);
//写属性时被调用
public virtual object TrySetMember(SetMemberBinder info, object value);
public virtual object TryDeleteMember(DeleteMemberBinder info); public virtual object TryUnaryOperation(UnaryOperationBinder info);
public virtual object TryBinaryOperation(BinaryOperationBinder info, object arg);
public virtual object TryConvert(ConvertBinder info);
public virtual object TryInvoke(InvokeBinder info, object[] args);
public virtual object TryInvokeMember(InvokeMemberBinder info, object[] args);
public virtual object TryCreateInstance(CreateInstanceBinder info, object[] args);
public virtual object TryGetIndex(GetIndexBinder info, object[] indices);
public virtual object TrySetIndex(SetIndexBinder info, object[] indices, object value);
public virtual object TryDeleteIndex(DeleteIndexBinder info, object[] indices);
public DynamicMetaObject IDynamicObject.GetMetaObject();
}