在C#中将实例定义为动态意味着:
编译器不执行编译时类型检查,但运行时检查就像对所有实例一样。
编译器不执行编译时类型检查,但与其他任何非动态实例不同,会进行运行时检查。
与2相同,这会带来性能损失(琐碎?可能很重要?)。
答案 0 :(得分:39)
问题非常混乱。
在C#中将实例定义为动态意味着:
通过“定义实例”,您的意思是“声明变量”吗?
编译器不执行编译时类型检查,但运行时检查就像它对所有实例一样。
“运行时检查一如既往”是什么意思?您有什么运行时检查?您是在考虑 IL验证程序执行的检查,还是在考虑由强制转换引起的运行时类型检查,或者是什么?
也许最好简单解释“动态”的作用。
首先,动态是从编译器 a 类型的角度出发的。从 CLR 的角度来看,没有 dynamic 这样的东西;在代码实际运行时,所有“动态”实例都已在生成的代码中替换为“object”。
编译器将类型的表达式视为 object 类型的表达式,除了对该表达式的值的所有操作进行分析,编译和执行在运行时基于实例的运行时类型。目标是执行的代码具有相同的语义,就好像编译器在编译时知道运行时类型一样。
您的问题似乎与性能有关。
回答性能问题的最佳方法是尝试并找出 - 如果您需要硬编号,您应该做的是使用动态和使用已知类型双向编写代码,以及然后拿出秒表并比较时间。这是了解的唯一方法。
但是,让我们从抽象层面考虑某些操作的性能影响。假设你有:
int x = 123;
int y = 456;
int z = x + y;
如今,在大多数硬件上添加两个整数大约需要十亿分之一秒。
如果我们让它变得动态会怎样?
dynamic x = 123;
dynamic y = 456;
dynamic z = x + y;
现在在运行时这是做什么的?这个框123和456分为对象,它们在堆上分配内存并进行一些复制。
然后它启动DLR并询问DLR“这个代码站点已经编译过一次,x和y的类型是int和int吗?”
本案的答案是否定的。然后,DLR启动C#编译器的特殊版本,该编译器分析添加表达式,执行重载解析,并吐出表达式树,描述将两个整数相加的lambda。然后,DLR将该lambda编译为动态生成的IL,然后jit编译器将其运行。然后,DLR缓存编译状态,以便您提出第二时间,编译器不必再完成所有工作。
更长而不是纳秒。它可能需要数千纳秒。
这会回答你的问题吗?我真的不明白你在这里问的是什么,但我正在做出最好的猜测。
答案 1 :(得分:7)
据我所知,答案是3。
你可以这样做:
dynamic x = GetMysteriousObject();
x.DoLaundry();
由于编译器没有对x
进行类型检查,它将编译此代码,假设您知道自己在做什么。
但这意味着必须进行额外的运行时检查:即检查x
的类型,查看它是否有DoLaundry
方法不接受任何参数,并执行它。
换句话说,上面的代码是类似就像这样做(我不是说它是相同的,只是绘制一个比较):
object x = GetMysteriousObject();
MethodInfo doLaundry = x.GetType().GetMethod(
"DoLaundry",
BindingFlags.Instance | BindingFlags.Public
);
doLaundry.Invoke(x, null);
这绝对不是一件轻而易举的事,但并不是说你的肉眼会发现性能问题。
我相信 dynamic
的实现涉及到为您完成的一些非常甜蜜的幕后缓存,因此如果您再次运行此代码并x
是同一类型,它运行得更快。
dynamic
没有那么多经验;这只是我理解它的工作方式。
答案 2 :(得分:2)
将变量声明为动态类似于将其声明为对象。动态只是获得另一个标记,表示成员解析延迟到运行时。
就性能损失而言 - 它取决于底层对象是什么。那是动态物体的全部意义吗?底层对象可以是Ruby或Python对象,也可以是C#对象。 DLR将在运行时计算出如何解析此对象上的成员调用,此解析方法将确定性能损失。
话虽如此 - 肯定会有性能损失。
这就是为什么我们不是简单地开始在整个地方开始使用动态对象。
答案 3 :(得分:2)
好吧,变量是静态类型的类型dynamic
但是除此之外,编译器不会进行任何检查。
类型绑定是在运行时完成的,是的,有一个惩罚,但如果dynamic
是唯一的选择那么那么。如果您可以使用静态类型解决问题,请执行此操作。话虽这么说,DLR确实调用了站点缓存,这意味着一些开销减少了,因为管道可以在某些情况下重用。
答案 4 :(得分:0)
我做了一个简单的测试:将100000000个赋值作为动态变量与相同数量的直接双精度赋值进行比较,例如
int numberOfIterations = 100000000;
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < numberOfIterations; i++)
{
var x = (dynamic)2.87;
}
sw.Stop();
sw.Restart();
for (int i = 0; i < numberOfIterations; i++)
{
double y = 2.87;
}
sw.Stop();
在第一个循环(带动态)中,它花费了大约500毫秒;在第二个大约200ms。当然,性能损失取决于您在循环中所做的事情,这些代表可能的最简单操作。
答案 5 :(得分:-1)
至于我不受欢迎dynamic
它只绕过编译时间检查。类型的分辨率在运行时发生,就像它对所有类型一样。所以我不认为它有任何性能损失。