C#4.0新增功能01 动态绑定 (dynamic 类型)

  C# 4 引入了一个新类型 dynamic。 该类型是一种静态类型,但类型为 dynamic 的对象会跳过静态类型检查。 大多数状况下,该对象就像具备类型 object 同样。 在编译时,将假定类型化为 dynamic 的元素支持任何操做。 所以,没必要考虑对象是从 COM API、从动态语言(例如 IronPython)、从 HTML 文档对象模型 (DOM)、从反射仍是从程序中的其余位置获取本身的值。 可是,若是代码无效,则在运行时会捕获到错误。  html

  在经过 dynamic 类型实现的操做中,该类型的做用是绕过编译时类型检查。 改成在运行时解析这些操做。 dynamic 类型简化了对 COM API(例如 Office Automation API)、动态 API(例如 IronPython 库)和 HTML 文档对象模型 (DOM) 的访问。编程

  在大多数状况下,dynamic 类型与 object 类型的行为相似。 可是,若是操做包含 dynamic类型的表达式,那么不会经过编译器对该操做进行解析或类型检查。 编译器将有关该操做信息打包在一块儿,以后这些信息会用于在运行时评估操做。 在此过程当中,dynamic 类型的变量会编译为 object 类型的变量。 所以,dynamic 类型只在编译时存在,在运行时则不存在。app

下面的示例将 dynamic 类型的变量与 object 类型的变量进行对比。 若要在编译时验证每一个变量的类型,请将鼠标指针放在 WriteLine 语句中的 dyn 或 obj 上。 IntelliSense 对 dyn 显示“dynamic” ,对 obj 显示“object” 。dom

class Program
{
    static void Main(string[] args)
    {
        dynamic dyn = 1;
        object obj = 1;

        System.Console.WriteLine(dyn.GetType());
        System.Console.WriteLine(obj.GetType());
    }
}

输出结果:编程语言

若要查看编译时 dyn 与 obj 之间的区别,请在前面示例的声明和 WriteLine 语句之间添加下列两行:ide

dyn = dyn + 3;
obj = obj + 3;

尝试在表达式 obj + 3 中添加整数和对象时,将报告编译器错误。 可是,对于 dyn + 3,不会报告任何错误。 在编译时不会检查包含 dyn 的表达式,缘由是 dyn 的类型为 dynamic函数

上下文

dynamic 关键字能够直接出现,也能够做为构造类型的组件在下列状况中出现:ui

  • 在声明中,做为属性、字段、索引器、参数、返回值、本地变量或类型约束的类型。下面的类定义在多个不一样的声明中使用 dynamicspa

class ExampleClass
{
    // 动态字段
    static dynamic field;

    // 动态属性
    dynamic prop { get; set; }

    // 动态返回类型和动态类型参数
    public dynamic exampleMethod(dynamic d)
    {
        // 局部动态变量
        dynamic local = "Local variable";
        int two = 2;

        if (d is int)
        {
            return local;
        }
        else
        {
            return two;
        }
    }
}
  • 在显式类型转换中,做为转换的目标类型。指针

static void convertToDynamic()
{
    dynamic d;
    int i = 20;
    d = (dynamic)i;
    Console.WriteLine(d);

    string s = "Example string.";
    d = (dynamic)s;
    Console.WriteLine(d);

    DateTime dt = DateTime.Today;
    d = (dynamic)dt;
    Console.WriteLine(d);

}
// 输出结果:
// 20
// Example string.
// 7/25/2018 12:00:00 AM
  • 在如下任何状况下:类型用做值(如 is 运算符或 as 运算符右侧),或者用做构造类型中 typeof 的参数。 例如,能够在下列表达式中使用 dynamic
int i = 8;
dynamic d;
// 使用 is 操做符
// 在此处动态类型和object类似,The dynamic type behaves like object。除非 somevar 的值为 null ,不然如下表达式将返回true
if (someVar is dynamic) { }

// 使用 as 操做符
d = i as dynamic;

// 使用typeof, 做为构造类型的一部分
Console.WriteLine(typeof(List<dynamic>));

// 如下语句致使编译器错误
//Console.WriteLine(typeof(dynamic));
示例
下面的示例在多个声明中使用 dynamic。 Main 方法也将编译时类型检查与运行时类型检查进行了对比。
using System;

namespace DynamicExamples
{
    class Program
    {
        static void Main(string[] args)
        {
            ExampleClass ec = new ExampleClass();
            Console.WriteLine(ec.exampleMethod(10));
            Console.WriteLine(ec.exampleMethod("value"));

            // 下面的语句会引起编译器异常。由于 exampleMethod 方法仅包含一个参数
            //Console.WriteLine(ec.exampleMethod(10, 4));

            dynamic dynamic_ec = new ExampleClass();
            Console.WriteLine(dynamic_ec.exampleMethod(10));

            // 由于 dynamic_ec 是 dynamic 类型, 下面的调用(传递了2个参数)不会引起编译器异常。
            // 可是在运行时会引起异常。
            //Console.WriteLine(dynamic_ec.exampleMethod(10, 4));
        }
    }

    class ExampleClass
    {
        static dynamic field;
        dynamic prop { get; set; }

        public dynamic exampleMethod(dynamic d)
        {
            dynamic local = "Local variable";
            int two = 2;

            if (d is int)
            {
                return local;
            }
            else
            {
                return two;
            }
        }
    }
}
// 输出结果:
// Local variable
// 2
// Local variable
使用 dynamic

  以上示例中,编译器的做用是将有关每一个语句的预期做用的信息一块儿打包到类型化为 dynamic 的对象或表达式。 在运行时,将对存储的信息进行检查,而且任何无效的语句都将致使运行时异常。

大多数动态操做的结果是其自己 dynamic。 例如,若是将鼠标指针放在如下示例中使用的 testSum 上,则 IntelliSense 将显示类型“(局部变量)dynamic testSum” 。

dynamic d = 1;
var testSum = d + 3;

System.Console.WriteLine(testSum);

结果不为 dynamic 的操做包括:

  • 从 dynamic 到另外一种类型的转换。
  • 包括类型为 dynamic 的自变量的构造函数调用。

例如,如下声明中 testInstance 的类型为 ExampleClass,而不是 dynamic

var testInstance = new ExampleClass(d);
转换

动态对象和其余类型之间的转换很是简单。 这样,开发人员将可以在动态行为和非动态行为之间切换。

任何对象均可隐式转换为动态类型,如如下示例所示。

dynamic d1 = 7;
dynamic d2 = "a string";
dynamic d3 = System.DateTime.Today;
dynamic d4 = System.Diagnostics.Process.GetProcesses();

反之,隐式转换也可动态地应用于类型为 dynamic 的任何表达式。

 

int i = d1;
string str = d2;
DateTime dt = d3;
System.Diagnostics.Process[] procs = d4;

 

使用类型为 dynamic 的参数重载决策
  若是方法调用中的一个或多个参数的类型为 dynamic,或者方法调用的接收方的类型为 dynamic,则会在运行时(而不是在编译时)进行重载决策。 在如下示例中,若是惟一可访问的 exampleMethod2 方法定义为接受字符串参数,则将 d1 做为参数发送不会致使编译器错误,但却会致使运行时异常。 重载决策之因此会在运行时失败,是由于 d1 的运行时类型为 int,而 exampleMethod2 要求为字符串。
ec.exampleMethod2("a string");

ec.exampleMethod2(d1);
动态语言运行时
  动态语言运行时 (DLR) 是 .NET Framework 4 中的一个新 API。 它提供了支持 C# 中 dynamic 类型的基础结构,还提供了 IronPython 和 IronRuby 等动态编程语言的实现。 有关 DLR 的详细信息,请参阅动态语言运行时概述
COM 互操做

C# 4 包括若干功能,这些功能改善了与 COM API(例如 Office 自动化 API)的互操做体验。 这些改进之处包括 dynamic 类型以及命名参数和可选参数的用法。

经过将类型指定为 object,许多 COM 方法都容许参数类型和返回类型发生变化。 这样,就必须显式强制转换值,以便与 C# 中的强类型变量保持协调。 若是使用 /link(C# 编译器选项)选项进行编译,则能够经过引入 dynamic 类型将 COM 签名中出现的 object 看做是 dynamic 类型,从而避免大量的强制转换。 例如,如下语句对比了在使用 dynamic 类型和不使用 dynamic 类型的状况下如何访问 Microsoft Office Excel 电子表格中的单元格。

// 引入动态以前
((Excel.Range)excelApp.Cells[1, 1]).Value2 = "Name";
Excel.Range range2008 = (Excel.Range)excelApp.Cells[1, 1];
// 在引入 dynamic 以后,对 value 属性的访问以及到 excel.range 的转换将由运行时 COM 绑定器处理
excelApp.Cells[1, 1].Value = "Name";
Excel.Range range2010 = excelApp.Cells[1, 1];
Title 说明
dynamic 描述 dynamic 关键字的用法。
动态语言运行时概述 提供有关 DLR 的概述,DLR 是一种运行时环境,它将一组适用于动态语言的服务添加到公共语言运行时 (CLR)。
演练:建立和使用动态对象 提供有关如何建立自定义动态对象以及建立访问 IronPython 库的对象的分步说明。
如何:经过使用 Visual C# 功能访问 Office 互操做对象 演示如何建立一个项目,该项目使用命名参数和可选参数、dynamic 类型以及可简化对 Office API 对象的访问的其余加强功能。
 
相关文章
相关标签/搜索