使用动态语言运行时(DLR)是否安全?如何在DLR中更改值类型?

时间:2014-08-28 08:33:05

标签: c# dynamic dynamic-language-runtime

我最近发现了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);
}

2 个答案:

答案 0 :(得分:2)

它和你一样安全。

在幕后,dynamic类型的变量实际上具有类型object。因此,当您为其分配"String"123new 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:运算符*无法应用于stringint类型的操作数。

您没有得到一些算术异常,因为它甚至从未尝试将"123"乘以2。运行时甚至找不到合适的*运算符来调用!运行时检查了bstring)和2int)的类型,并尝试为这两种类型找到运算符*,但无法&# 39;找不到......因此是例外。

(当然a * 2也是如此;运行时看到a有运行时类型int(因为它引用了特定的盒装整数123 ({1}}以及2的运算符*被发现并因此被调用。)

顺便说一下,由于int变量的后期绑定特性(即对它们的合适操作只在运行时计算出来),IntelliSense(编译时功能)不适用于它们。

答案 1 :(得分:1)

在您的代码dyn中包含引用,每次重新分配dyn时,您都会重新分配此引用。如果在重新分配之前引用的dyn现在可以被垃圾收集,如果该对象不存在其他引用。将值类型分配给dynamic时,该值将被装箱,因此dyn = 123将在堆上创建一个装箱的int,并且在重新分配dyn时,此装箱的int可以被垃圾收集。 / p>

dynamic所做的是,任何涉及dynamic变量的方法都是在运行时根据变量引用的对象的运行时类型决定的,而不是&#34 ;正常&#34; C#其中方法在编译时确定,或者是简单的虚方法表查找。如果你尝试做一些不可能的事情,你会得到一个例外,但是在使用dynamic时会出现这种情况。

总而言之,dynamic变量包含一个引用,就像任何其他引用类型变量一样。但是,使用dynamic变量时生成的代码非常不同,因为调用的实际方法只能在运行时确定。