Использование типа dynamic (Руководство по программированию на C#)

В Visual C# 2010 появился новый тип — dynamic. Тип является статическим типом, но объект типа dynamic обходит проверку статического типа. В большинстве случаев он функционирует, как тип object. Во время компиляции предполагается что элементы с типом dynamic поддерживают любые операции. Поэтому разработчику не нужно следить за тем, откуда объект получает свое значение — из интерфейса API COM, из динамического языка, такого как IronPython, из объектной модели DOM HTML, из отражения или из любого другого места программы. Но если код является недействительным, во время выполнения перехватываются ошибки.

Например, если у метода exampleMethod1 экземпляра в следующем коде имеется только один параметр, компилятор определяет, что первый вызов метода (ec.exampleMethod1(10, 4)) является недопустимым, поскольку он содержит два аргумента. Такой вызов приводит к ошибке компилятора. Второй вызов метода dynamic_ec.exampleMethod1(10, 4) не проверяется компилятором, поскольку тип dynamic_ec является типом dynamic. Поэтому ошибка компилятора не возникает. Однако ошибка не остается незамеченной и не приводит к неопределенному результату. Она перехватывается во время выполнения и вызывает исключение времени выполнения.

static void Main(string[] args)
{
    ExampleClass ec = new ExampleClass();
    // The following line causes a compiler error if exampleMethod1 has only
    // one parameter.
    //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 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

Среда DLR — это новый интерфейс API в .NET Framework 4. Она обеспечивает инфраструктуру, поддерживающую тип dynamic в C#, а также реализацию языков динамического программирования, таких как IronPython и IronRuby. Дополнительные сведения о спецификации DLR см. в разделе Общие сведения о среде DLR.

COM-взаимодействие

В Visual C# 2010 имеется несколько функций, улучшающих взаимодействие с интерфейсами API COM, такими как API автоматизации Office. К таким усовершенствованиями относятся тип dynamic и именованные и необязательные аргументы.

Многие методы COM допускают изменение типов аргументов и возвращаемых типов за счет определение типов в виде object. Ранее это требовало явного приведения значений в соответствии со строго типизированными переменными в C#. При компиляции с использованием параметра /link (параметры компилятора C#) появление типа dynamic позволяет обрабатывать вхождения object в сигнатурах COM, как если бы они имели тип dynamic, и, следовательно, избегать большей части операций приведения. Например, следующие инструкции показывают различия в обращении к ячейке в таблице Microsoft Office Excel с использованием типа dynamic и без использования типа dynamic.

// Before the introduction of dynamic.
((Excel.Range)excelApp.Cells[1, 1]).Value2 = "Name";
Excel.Range range2008 = (Excel.Range)excelApp.Cells[1, 1];
// After the introduction of dynamic, the access to the Value property and
// the conversion to Excel.Range are handled by the run-time COM binder.
excelApp.Cells[1, 1].Value = "Name";
Excel.Range range2010 = excelApp.Cells[1, 1];

Связанные разделы

Заголовок

Описание

dynamic (Справочник по C#)

Описание использования ключевого слова dynamic.

Общие сведения о среде DLR

Обзор среды DLR, которая представляет собой среду выполнения, добавляющую набор служб для динамических языков в среду CLR.

Пошаговое руководство. Создание и использование динамических объектов (C# и Visual Basic)

Предоставление пошаговых руководств для создания пользовательских динамических объектов и проекта, который имеет доступ к библиотеке IronPython.

Практическое руководство. Доступ к объектам взаимодействия Office с помощью функций языка Visual C# 2010 (Руководство по программированию на C#)

Демонстрация процедуры создания проекта, использующего именованные и необязательные аргументы, тип dynamic и другие усовершенствованные возможности, которые упрощают обращение к объектам API Office.