C#动态关键字 – 运行时惩罚?

在C#中将实例定义为动态意味着:

  1. 编译器不执行编译时类型检查,但运行时检查就像对所有实例一样。

  2. 编译器不执行编译时类型检查,但运行时检查发生,与任何其他非动态实例不同。

  3. 与2相同,这会带来性能损失(微不足道的?潜在的重要性?)。

这个问题非常令人困惑。

在C#中将实例定义为动态意味着:

通过“定义实例”,您的意思是“声明一个变量”吗?

编译器不执行编译时类型检查,但运行时检查就像对所有实例一样。

“像往常一样运行时检查”是什么意思? 您有什么运行时检查? 您是在考虑ILvalidation程序执行的检查,还是在考虑由强制转换引起的运行时类型检查,或者是什么?

或许最好简单解释“动态”的作用。

首先, 动态是从编译器的角度来看的。 从CLR的角度来看,没有动态的东西; 在代码实际运行时,所有“动态”实例都已在生成的代码中替换为“对象”。

编译器将dynamic类型的表达式完全视为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的表达式树 ,它将两个int加在一起。 然后,DLR将该lambda编译为动态生成的IL,然后jit编译器就会执行此操作。 然后,DLR缓存编译状态,以便第二次询问时,编译器不必再执行所有操作。

这需要超过一纳秒。 它可能需要数千纳秒。

这会回答你的问题吗? 我真的不明白你在这里问的是什么,但我正在做出最好的猜测。

据我所知,答案是3。

你可以这样做:

 dynamic x = GetMysteriousObject(); x.DoLaundry(); 

由于编译器没有对x类型检查,因此它将编译此代码,假设您知道自己在做什么。

但这意味着必须进行额外的运行时检查:即检查x的类型,查看它是否具有DoLaundry接受任何参数的DoLaundry方法,并执行它。

换句话说,上面的代码有点像这样做(我不是说它是相同的,只是绘制一个比较):

 object x = GetMysteriousObject(); MethodInfo doLaundry = x.GetType().GetMethod( "DoLaundry", BindingFlags.Instance | BindingFlags.Public ); doLaundry.Invoke(x, null); 

这绝对不是微不足道的,尽管这并不是说你将能够用肉眼看到性能问题。

相信 dynamic的实现涉及到为你完成的一些非常甜蜜的幕后缓存,所以如果再次运行此代码并且x是相同的类型,它将运行得更快。

不过,不要抱我这么做。 我对dynamic没有那么多经验; 这只是我理解它的工作方式。

将变量声明为动态类似于将其声明为对象 。 动态只是获取另一个标志,表明成员解析被延迟到运行时

在性能损失方面 – 它取决于底层对象是什么。 那是动态物体的全部意义吗? 底层对象可以是Ruby或Python对象,也可以是C#对象。 DLR将在运行时计算出如何解析此对象上的成员调用,此解析方法将确定性能损失。

话虽如此 – 肯定会有性能损失。

这就是为什么我们不是简单地开始在整个地方开始使用动态对象。

好吧,变量是静态类型的dynamic类型,但除此之外,编译器不会做任何检查,据我所知。

类型绑定在运行时完成,是的,有一个惩罚,但如果dynamic是唯一的选择,那么什么。 如果您可以使用静态类型解决问题,请执行此操作。 话虽这么说,DLR确实调用了站点缓存,这意味着一些开销减少了,因为在某些情况下可以重用管道。

到目前为止,我只是绕过编译时检查。 类型的分辨率在运行时发生,就像它对所有类型一样。 所以我不认为有任何与之相关的性能损失。