Console.WriteLine("Переменная val теперь содержит: " + val + '\n');
string str2 = str.ToLower(CultureInfo.CurrentCulture);
Console.WriteLine("Переменная str2 содержит: " + str2);
// Поддерживаются неявные преобразования из динамических типов.
int x = val * 2;
Console.WriteLine("Переменная x содержит: " + x);
}
}
Выполнение этой программы дает следующий результат.
Переменная str содержит: Это строка
Переменная val содержит: 10
Переменная str теперь содержит: ЭТО СТРОКА
Переменная val теперь содержит: 12
Переменная str2 содержит: это строка
Переменная х содержит: 24
Обратите внимание в этой программе на две переменные str
и val
, объявляемые с помощью типа dynamic
. Это означает, что проверка на соответствие типов операций с участием обеих переменных не будет произведена во время компиляции. В итоге для них оказывается пригодной любая операция. В данном случае для переменной str
вызываются методы ToUpper()
и ToLower()
класса String
, а переменная участвует в операциях сложения и умножения. И хотя все перечисленные выше действия совместимы с типами объектов, присваиваемых обеим переменным в рассматриваемом здесь примере, компилятору об этом ничего не известно — он просто принимает. И это, конечно, упрощает программирование динамических процедур, хотя и допускает возможность Появления ошибок в подобных действиях во время выполнения.
В разбираемом здесь примере программа ведет себя "правильно" во время выполнения, поскольку объекты, присваиваемые упомянутым выше переменным, поддерживают действия, выполняемые в программе. В частности, переменной val
присваивается целое значение, и поэтому она поддерживает такие целочисленные операции, как сложение. А переменной str
присваивается символьная строка, и поэтому она поддерживает строковые операции. Следует, однако, иметь в виду, что ответственность за фактическую поддержку типом объекта, на который делается ссылка, всех операций над данными типа dynamic возлагается на самого программирующего. В противном случае выполнение программы завершится аварийным сбоем.
В приведенном выше примере обращает на себя внимание еще одно обстоятельство: переменной типа dynamic
может быть присвоен любой тип ссылки на объект благодаря неявному преобразованию любого типа в тип dynamic
. Кроме того, тип dynamic
автоматически преобразуется в любой другой тип. Разумеется, если во время выполнения такое преобразование окажется неправильным, то произойдет ошибка при выполнении. Так, если добавить в конце рассматриваемой здесь программы следующую строку кода:
bool b = val;
то возникнет ошибка при выполнении из-за отсутствия неявного преобразования типа int
(который оказывается типом переменной val
во время выполнения) в тип bool
. Поэтому данная строка кода приведет к ошибке при выполнении, хотя она и будет скомпилирована безошибочно.
Прежде чем оставить данный пример программы, попробуйте поэкспериментировать с ней. В частности, измените тип переменных str
и val
на object
, а затем попытайтесь скомпилировать программу еще раз. В итоге появятся ошибки при компиляции, поскольку тип object
не поддерживает действия, выполняемые над обеими переменными, что и будет обнаружено во время компиляции. В этом, собственно, и заключается основное отличие типов object
и dynamic
. Несмотря на то что оба типа могут использоваться для ссылки на объект любого другого типа, над переменной типа object
можно производить только те действия, которые поддерживаются типом object
. Если же вы используете тип dynamic
, то можете указать какое угодно действие, при условии что это действие поддерживается конкретным объектом, на который делается ссылка во время выполнения.