通过IL Emit来创建类型的探究

  最近刚开始研究IL,起源是看到Odin内部源码创建一个Type使用了这种做法,当时好奇为什么要这么做。

  先丢出代码例子:

通过IL Emit来创建类型的探究
 1 class TestClass 
 2         {
 3             public TestClass() 
 4             {
 5                 mylist = new List<int>();
 6                 for(int i=0;i<100;i++) 
 7                 {
 8                     mylist.Add(i);
 9                 }
10             }
11 
12             public int x = 5;
13             public List<int> mylist;
14         }
测试类代码 通过IL Emit来创建类型的探究
 1 // Do Some Test
 2             int needCnt = 10000;
 3             var preTime = EditorApplication.timeSinceStartup;
 4             for(int i=0;i<needCnt;i++) 
 5             {
 6                 TestClass t = new TestClass();
 7             }
 8             var nowTime = EditorApplication.timeSinceStartup;
 9             Debug.Log("通常创建的时间 " + (nowTime - preTime));
10 
11             var type = typeof(TestClass);
12             var constructor = type.GetConstructor(Type.EmptyTypes);
13             var method = new DynamicMethod(type.FullName + "_FastCreator", type, Type.EmptyTypes);
14 
15             var il = method.GetILGenerator();
16 
17             il.Emit(OpCodes.Newobj, constructor);
18             il.Emit(OpCodes.Ret);
19 
20             var fastCreator = (Func<TestClass>)method.CreateDelegate(typeof(Func<TestClass>));
21             
22             preTime = EditorApplication.timeSinceStartup;
23             for(int i=0;i<needCnt;i++) 
24             {
25                 var t = constructor.Invoke(new object[] {});
26             }
27             nowTime = EditorApplication.timeSinceStartup;
28             Debug.Log("构造函数Invoke并且不转型创建的时间 " + (nowTime - preTime));
29 
30             preTime = EditorApplication.timeSinceStartup;
31             for(int i=0;i<needCnt;i++) 
32             {
33                 TestClass t = constructor.Invoke(new object[] {}) as TestClass;
34             }
35             nowTime = EditorApplication.timeSinceStartup;
36             Debug.Log("构造函数Invoke创建的时间 " + (nowTime - preTime));
37 
38             preTime = EditorApplication.timeSinceStartup;
39             for(int i=0;i<needCnt;i++) 
40             {
41                 TestClass t = fastCreator();
42             }
43             nowTime = EditorApplication.timeSinceStartup;
44             Debug.Log("Emit创建的时间 " + (nowTime - preTime));
测试代码逻辑

  测试结果如下(直接在Unity上跑的):

通过IL Emit来创建类型的探究

  看起来的结果就是,通过IL Emit的时间跟直接new一个的时间是同一个数量级别的,通过method.Invoke的时间要慢上一倍。

  个人猜测Odin选择这种做法来创建种种类型的原因如下:1. 时间上比Invoke要快 2. 只有Type信息无法调用new(猜测?)3. 方便制造成一个委托,下次再用。

  以后有更多心得了再补充。。。

  

 

上一篇:flask 在线预览二进制文本


下一篇:unable to delete * (must be forced) - image is referenced in multiple repositories