.Net中各种不同的对象创建方式的速度差异四

资讯 驱动中国 sevenleaf 2,588 次阅读 0 条评论
分享 Q

      在这片文章中,我们暂时放一放Activator.CreateInstance(Type)和Activator.CreateInstance<T>()之间的性能差异,去探索一下,为什么使用泛型约束的速度和CreateInstance<T>()差不多(用屁股都能猜到应该是直接调用了CreateInstance<T>())。
      首先我们写一个小程序来验证我们的猜想:

1 using System;
2
3 namespace GenericNew
4 {
5     public class Program
6     {
7         public static void Main(string[] args)
8         {
9             CreateInstance<Program>();
10             new Program();
11         }
12    
13         public static T CreateInstance<T>() where T: new()
14         {
15             return new T();
16         }
17     }
18 }
      编译了以后用reflector来查看编译的结果:

1 public static T CreateInstance<T>() where T: new()
2 {
3     return new T();
4 }
      看起来没有什么问题啊,跟写的时候一样美妙,也没有见到System.Activator.CreateInstance<T>()的踪影。

      那么,让我们切换到msil模式看看:

1 .method public hidebysig static !!T CreateInstance<.ctor T>() cil managed
2 {
3     .maxstack 2
4     .locals init (
5         [0] !!T local,
6         [1] !!T local2)
7     L_0000: nop
8     L_0001: ldloca.s local2
9     L_0003: initobj !!T
10     L_0009: ldloc.1
11     L_000a: box !!T
12     L_000f: brfalse.s L_001c
13     L_0011: ldloca.s local2
14     L_0013: initobj !!T
15     L_0019: ldloc.1
16     L_001a: br.s L_0021
17     L_001c: call !!0 [mscorlib]System.Activator::CreateInstance<!!T>()
18     L_0021: stloc.0
19     L_0022: br.s L_0024
20     L_0024: ldloc.0
21     L_0025: ret
22 }
      恩,发现[mscorlib]System.Activator::CreateInstance<!!T>()了,通过分析这段代码,我们会发现,其实ms对于这个的性能还是做了一定的优化的,这段代码:

      试图采用值类型的初始化方法初始化对象,并对该对象进行装箱操作。
      装箱失败的情况下,调用System.Activator.CreateInstance<T>()来创建对象。
      最后再返回创建好的对象。

      那么是不是.net本来就是通过这种方式来创建对象的呢?

      我们来对比一下new Program()这条语句的编译结果:

1 newobj instance void GenericNew.Program::.ctor()

      那么为什么c#编译器没有采用这个指令来创建泛型类的实例呢?

      我们需要参考一下msdn上对于newobj的用法的定义:

      http://msdn.microsoft.com/en-us/library/system.reflection.emit.opcodes.newobj(VS.85).aspx

      在这里,我们看到,newobj指令的使用方法是 newobj <ctor>

      也就是说,它的参数是构造器,而非类型本身; 原因就在于,.Net允许有不同参数的构造器存在,只有指定了构造器,clr才知道要使用哪个构造器来初始化对象。

      而,对于一个泛型类,在编译器是无法知道它的泛型参数的构造器信息的,自然就没有办法使用newobj指令了。

版权声明:本文由驱动中国整理发布,转载需注明出处与原文链接。如有疑问请联系 editor@qudong.com
本文价值 成为第一个评分的人
登录后为本文打分
网友评论0 条评论
正在回复 的评论取消
评论加载中…
🔐

登录后参与互动

评论、点赞均可赚积分
连续签到、邀请好友也有奖励 🎁

电脑端: 微信扫码登录 微信内: 一键登录

微信扫一扫

打开微信「扫一扫」,分享本文到朋友圈或好友