最近學習了msil,發現了不少好玩的,今天介紹一個用IL來建立對象的方式c#
public static T Create<T>() where T : new() { return new T(); } public static object CreateNative() { return new object(); }
寫一個測試幫助方法簡單的測試下這兩個方法的執行時間的長短:工具
public static void Measure(string what, int reps, Action action) { action(); //warm up double[] results = new double[reps]; for (int i = 0; i < reps; i++) { Stopwatch sw = Stopwatch.StartNew(); action(); results[i] = sw.Elapsed.TotalMilliseconds; } Console.WriteLine("{0} - AVG = {1}, MIN = {2}, MAX = {3}", what, results.Average(), results.Min(), results.Max()); }
調用測試方法:學習
int reps = 5; int its = 100000; Measure("create", reps, () => { for (int i = 0; i < its; i++) { Create<object>(); } }); GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); Measure("createNative", reps, () => { for (int i = 0; i < its; i++) { CreateNative(); } });
執行結果:測試
能夠經過測試結果看出來本地方法建立的比泛型方式建立的消耗的時間短,這是爲何。用工具查看生成的il就能夠發現爲何了。
泛型方式生成的IL以下:
本地方式的生成IL以下:
能夠看出泛型方式生成的IL裏面調用了Activator.CreateInstance方法,而本地方式而直接new一個對象。因此本地方式的生成對象要比泛型方式用時短。既然這樣直接經過Activator.CreateInstance 生成對象呢。ui
public static object CreateReflect(Type type) { return Activator.CreateInstance(type); }
如今再來比較這三種的生成方式的用時長短,用一樣的方式調用CreateReflect,獲得結果以下:
從結果上看能夠看出最快的是本地直接new,第二快是經過Activator.CreateInstance,最慢的則是泛型實例化建立對象。
在工做中泛型建立對象很常見。如何解決泛型建立對象慢的問題呢?pwa
public class CreationHelper<T> where T : new() { public static Func<T> objCreator = null; public static T New() { if (objCreator == null) { Type objectType = typeof(T); ConstructorInfo defaultCtor = objectType.GetConstructor(new Type[] { }); DynamicMethod dynMethod = new DynamicMethod( name: string.Format("_{0:N}", Guid.NewGuid()), returnType: objectType, parameterTypes: null); var gen = dynMethod.GetILGenerator(); gen.Emit(OpCodes.Newobj, defaultCtor); gen.Emit(OpCodes.Ret); objCreator = dynMethod.CreateDelegate(typeof(Func<T>)) as Func<T>; } return objCreator(); } }
用以上相同的方式來測試,測試代碼:3d
GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); Measure("DynamicCreate", reps, () => { for (int i = 0; i < its; i++) { CreationHelper<object>.New(); } });
測試結果以下:
結果一目瞭然,IL方式建立對象的用時在本地實例化和Activator.CreateInstance之間,只比本地實例化稍慢。因此泛型實例化能夠考慮這種方式,能夠提高泛型實例化的效率。code
本文介紹了c#建立對象的4種方式,簡單的比較了這四種建立效率。說明了IL的效率果真是高。學會了高效的建立泛型對象的一種方式。orm