使用类型 dynamic

dynamic 类型是一种静态类型,但类型为 dynamic 的对象会跳过静态类型检查。 大多数情况下,该对象就像具有类型 object 一样。 编译器假定 dynamic 元素支持任何操作。 因此,无需确定对象是从 COM API、动态语言(例如 IronPython)、HTML 文档对象模型 (DOM)、反射还是程序中的其他位置获取自己的值。 但是,如果代码无效,则会在运行时出现错误。

例如,如果以下代码中的实例方法 exampleMethod1 只有一个形参,则编译器会将对该方法的第一个调用 ec.exampleMethod1(10, 4) 识别为无效,因为它包含两个实参。 该调用将导致编译器错误。 编译器不会检查对该方法的第二个调用 dynamic_ec.exampleMethod1(10, 4),因为 dynamic_ec 的类型为 dynamic。 因此,不会报告编译器错误。 但是,该错误不会被无限期疏忽。 它将在运行时出现,并导致运行时异常。

static void Main(string[] args)
{
    ExampleClass ec = new ExampleClass();
    // The following call to exampleMethod1 causes a compiler error
    // if exampleMethod1 has only one parameter. Uncomment the line
    // to see the error.
    //ec.exampleMethod1(10, 4);

    dynamic dynamic_ec = new ExampleClass();
    // The following line is not identified as an error by the
    // compiler, but it causes a run-time exception.
    dynamic_ec.exampleMethod1(10, 4);

    // The following calls also do not cause compiler errors, whether
    // appropriate methods exist or not.
    dynamic_ec.someMethod("some argument", 7, null);
    dynamic_ec.nonexistentMethod();
}
class ExampleClass
{
    public ExampleClass() { }
    public ExampleClass(int v) { }

    public void exampleMethod1(int i) { }

    public void exampleMethod2(string str) { }
}

在这些示例中,编译器的作用是将有关每个语句的预期作用的信息一起打包到 dynamic 对象或表达式。 运行时检查存储的信息,任何无效的语句都会导致运行时异常。

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

dynamic d = 1;
var testSum = d + 3;
// Rest the mouse pointer over testSum in the following statement.
System.Console.WriteLine(testSum);

结果不为 dynamic 的操作包括:

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

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

var testInstance = new ExampleClass(d);

转换

动态对象和其他类型之间的转换非常简单。 转换使开发人员能够在动态行为和非动态行为之间切换。

可以将任何内容隐式转换为 dynamic,如以下示例所示。

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 要求为字符串。

// Valid.
ec.exampleMethod2("a string");

// The following statement does not cause a compiler error, even though ec is not
// dynamic. A run-time exception is raised because the run-time type of d1 is int.
ec.exampleMethod2(d1);
// The following statement does cause a compiler error.
//ec.exampleMethod2(7);

动态语言运行时

动态语言运行时 (DLR) 提供了支持 C# 中 dynamic 类型的基础结构,还提供了 IronPython 和 IronRuby 等动态编程语言的实现。 有关 DLR 的详细信息,请参阅动态语言运行时概述

COM 互操作

通过将类型指定为 object,许多 COM 方法都允许参数类型和返回类型发生变化。 COM 互操作要求必须显式强制转换值,以便与 C# 中的强类型变量保持协调。 如果使用 EmbedInteropTypes(C# 编译器选项)选项进行编译,则可以通过引入 dynamic 类型将 COM 签名中出现的 object 看作是 dynamic 类型,从而避免大量的强制转换。 有关将 dynamic 类型与 COM 对象配合使用的详细信息,请参阅有关如何使用 C# 功能访问 Office 互操作对象的文章。

Title 描述
dynamic 描述 dynamic 关键字的用法。
动态语言运行时概述 提供有关 DLR 的概述,DLR 是一种运行时环境,它将一组适用于动态语言的服务添加到公共语言运行时 (CLR)。
演练:创建和使用动态对象 提供有关如何创建自定义动态对象以及创建访问 IronPython 库的对象的分步说明。