Безопасно ли использовать динамическую языковую среду выполнения (DLR)? Как можно изменить тип значения в DLR?

Как я недавно обнаружил DLR, я вижу, что можно легко изменять типы значений во время выполнения. Будут ли какие-либо проблемы с памятью или исключения во время выполнения? Как DLR может изменить значение без каких-либо исключений и / или ошибок памяти? Не изменился ли адрес объекта после изменения значения? что происходит со старым значением / объектом и его адресом / ссылкой?

dynamic dyn = "String";

Console.Write(dyn);

dyn = 123;

Console.Write(dyn * 2);

dyn = new Action<string>(Test);

dyn("ABC");

static void Test(string t)
{
    Console.WriteLine(t);
}

person 111WARLOCK111    schedule 28.08.2014    source источник


Ответы (2)


Это так же безопасно, как и вы.

Под капотом переменная типа dynamic на самом деле имеет тип object. Так что ничего особенного не происходит, когда вы назначаете ему "String", 123 или new Action<string>(…). Возможно, вы уже знаете, что вы легко можете сделать то же самое с любой object переменной. Единственная магия, которая происходит, - это бокс для значений, типизированных для значений (например, 123), но опять же, это не является чем-то особенным для dynamic, но произошло с такими присваиваниями, как object x = 123;, начиная с первой версии .NET.

(Для ясности: вы не меняете никакого значения, когда повторно назначаете свою dyn переменную. Вы просто делаете dyn ссылку на другое значение.)

Волшебство, которое случается с dynamic, - это позднее связывание. То есть каждый раз, когда вы вызываете метод, свойство, оператор и т. Д. Для такой переменной, фактический метод, свойство, оператор и т. Д. Еще не известен во время компиляции; он выбирается во время выполнения. Для каждого такого вызова компилятор генерирует код, который проверяет тип текущего значения переменной и пытается выбрать подходящий метод, свойство, оператор и т. Д. Для вызова. Если такой найден, он вызывается; в противном случае вы получите исключение.

Давайте посмотрим на другой пример:

dynamic a = 123;
Console.WriteLine(a * 2); // OK

dynamic b = "123";
Console.WriteLine(b * 2); // will throw an exception

Здесь интересно исключение, выброшенное вторым блоком:

RuntimeBinderException: оператор * нельзя применять к операндам типа string и int.

Вы не получили какое-то арифметическое исключение, потому что никогда даже не пытались умножить "123" на 2. Среда выполнения не смогла даже найти подходящий * оператор для вызова! Среда выполнения проверила типы b (string) и 2 (int) и попыталась найти оператор * для этих двух типов, но не смогла его найти… следовательно, исключение.

(То же самое, конечно, произошло с a * 2; там среда выполнения увидела, что a имеет тип времени выполнения int (поскольку он ссылается на упакованное целое число 123 в тот конкретный момент), и то же самое произошло с 2, и был найден и, таким образом, вызван оператор * для двух ints .)

Кстати, из-за природы dynamic переменных с поздним связыванием (т.е. подходящие действия с ними выясняются только во время выполнения), IntelliSense (функция времени компиляции) с ними не работает.

person stakx - no longer contributing    schedule 28.08.2014

В вашем коде dyn содержится ссылка, и каждый раз, когда вы переназначаете dyn, вы переназначаете эту ссылку. Все, на что dyn ссылались перед переназначением, теперь можно собрать мусором, если на этот объект не существует других ссылок. Когда вы назначаете тип значения для dynamic, значение будет помещено в коробку, поэтому dyn = 123 создаст в куче упакованное целое число, а при переназначении dyn это упакованное целое число может быть собрано в мусор.

Что делает dynamic, так это то, что любые вызываемые методы, которые включают dynamic variabled, определяются во время выполнения на основе типа времени выполнения объекта, на который ссылается переменная, в отличие от "обычного" C #, где методы определяются во время компиляции или являются простой поиск в таблице виртуальных методов. И если вы попытаетесь сделать что-то невозможное, вы получите исключение, но это ожидается при использовании dynamic.

Подводя итог, можно сказать, что переменная dynamic содержит ссылку, как и любая другая переменная ссылочного типа. Однако код, сгенерированный при использовании переменной dynamic, очень отличается, поскольку фактический вызываемый метод может быть определен только во время выполнения.

person Martin Liversage    schedule 28.08.2014