`

What's New in C# 4.0 之一 语法

阅读更多
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();
}


分享到:
评论
1 楼 RednaxelaFX 2009-06-08  
期待ray_linn大大原本计划写的C#特性介绍系列~

话说C# 4.0的dynamic貌似不是基于DynamicObject抽象类实现的?就C#小组所关注的部分来看,最核心的貌似是C#的binder,其它都是DLR小组的工作。毕竟dynamic特性能对任何.NET对象起作用,而一般的CLR类的对象都不是继承DynamicObject的。C#的binder倒是依赖于另一个类,DynamicMetaObject,用来传递约束信息。DLR的binder一般是先让对象自己提供DynamicMetaObject(这也就是IDynamicObject的意义),如果有的话就让DMO来解决bind的问题;如果对象自己没有提供DMO,就有各个语言自己实现的binder来解决;如果某个语言没有实现自己的binder,或者某个对象它无法bind,就扔给DLR的默认binder上……都不行就撂下一个异常,吐口事后烟,收工。

ray_linn大大想说的是如果用C# 4.0自定义dynamic对象行为的时候,可以继承DynamicObject,是这个意思吗?

相关推荐

Global site tag (gtag.js) - Google Analytics