代码改变世界

关于C#的dynamic类型,简单演示及说明

2012-05-30 11:06  Andrew.Wangxu  阅读(2403)  评论(0编辑  收藏  举报

在阅读《CLR via C# (第三版)》第132页看到dynamic这个类型,感觉挺有用的。

记录下来日后查用以及跟园友们分享,内容如下:

 

    为了方便开发人员使用反射或者与基本组件通信,C#编译器允许将一个表达式的类型标记为 dynamic。还可以将一个表达式的结果放到一个变量中,并将变量的类型标记为dynamic。然后,可以用这个 dynamic 表达式/变量调用一个成员,比如字段、属性/索引器、方法、委托以及一元/二元/转换操作符。代码用 dynamic 表达式/变量来调用一个成员时,编译器会生成特殊的 IL 代码来描述所需的操作。这种特殊的代码成为 payload(有效载荷)。在运行时,payload 代码根据当前由 dynamic 表达式/变量引用的对象的实际类型来决定具体执行的操作。

 

以下代码对此进行了演示:

 

using System;

internal static class DynamicDemo
{
    public static void Main()
    {
        for (int i = 0; i < 2; i++)
        {
            dynamic arg = (i == 0) ? (dynamic)5 : (dynamic)"A";
            dynamic result = Plus(arg);
            M(result);
        }
    }

    private static dynamic Plus(dynamic arg)
    {
        return arg + arg;
    }

    private static void M(int n)
    {
        Console.WriteLine("M(int):" + n);
    }

    private static void M(string s)
    {
        Console.WriteLine("M(string):" + s);
    }
}

 

以上代码是经过了测试的,如果在编译过程中出现错误,可能缺少引用,比如:Microsoft.CSharp

------------------------------------------------------------

执行 Main 方法时,会得到以下输出:

M(int):10

M(string):AA

 

为了理解发生的事情,让我们先来研究以下 Plus 方法。这个方法将参数的类型声明为 dynamic。在方法内部,实参被作为二元+操作符的两个操作数使用。由于 arg 是 dinamic ,所以C#编译器会生成 payload 代码,以便在运行时检查 arg 的实际类型,并决定 + 操作符实际要做的事情。

 

第一次调用Plus时,传递的是5(一个int),所以Plus向它的调用者返回值10(也是一个int)。结果放到result变量(声明为 dynamic 类型)中。然后调用M方法,将 result 传给它。针对对 M 的调用,编译器会生成 payload 代码,以便在运行时检查传给M的值的实际类型,并决定应该调用 M 方法的哪个重载版本。在 result 包含一个 int 的前提下,调用的是获取一个 int 参数的 M 重载。

 

第二次调用Plus时,传递的是"A"(一个string),所以 Plus 会将 "AA" ("A"和它自己的连接的结果)传回它的调用者,后者将这个结果放到 result 变量中。然后,再次调用 M 方法,将 result 传给他。 这一次, payload 代码判断出传给 M 的值的实际类型是 String , 所以会调用获取一个 String 参数的 M 重载。

 

--------------------------------------

以及关于更多的 dynamic 的说明以及实现过程,这里就不做更多的介绍了,园友们可以参考《CLR via C# (第三版)》第133页,或者查下MSDN文档吧

 

参考:http://www.wxzzz.com/?id=95