Created
May 5, 2015 18:46
-
-
Save svick/ebf10598a61a40548325 to your computer and use it in GitHub Desktop.
Improved Activator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Diagnostics; | |
| using System.Linq; | |
| using System.Linq.Expressions; | |
| using System.Reflection.Emit; | |
| namespace ConsoleApplication1 | |
| { | |
| class Program | |
| { | |
| static void Main() | |
| { | |
| int n = 1000; | |
| //MeasureOld(n); | |
| //MeasureNew(n); | |
| //MeasureOld2(n, 42, "foo"); | |
| MeasureNew2(n, 42, "foo"); | |
| } | |
| private static void MeasureOld(int n) | |
| { | |
| var stopwatch = Stopwatch.StartNew(); | |
| var c = Activator.CreateInstance<C>(); | |
| stopwatch.Stop(); | |
| Console.WriteLine(stopwatch.Elapsed.TotalMilliseconds); | |
| stopwatch.Restart(); | |
| for (int i = 0; i < n; i++) | |
| Activator.CreateInstance<C>(); | |
| stopwatch.Stop(); | |
| Console.WriteLine(stopwatch.Elapsed.TotalMilliseconds / n * 1000); | |
| } | |
| private static void MeasureNew(int n) | |
| { | |
| var stopwatch = Stopwatch.StartNew(); | |
| var c = MyActivator<Func<C>>.GetDelegate()(); | |
| stopwatch.Stop(); | |
| Console.WriteLine(stopwatch.Elapsed.TotalMilliseconds); | |
| stopwatch.Restart(); | |
| for (int i = 0; i < n; i++) | |
| MyActivator<Func<C>>.GetDelegate()(); | |
| stopwatch.Stop(); | |
| Console.WriteLine(stopwatch.Elapsed.TotalMilliseconds / n * 1000); | |
| } | |
| private static void MeasureOld2(int n, int p1, string p2) | |
| { | |
| var stopwatch = Stopwatch.StartNew(); | |
| var args = new object[] { p1, p2 }; | |
| var c = (C)Activator.CreateInstance(typeof(C), args); | |
| stopwatch.Stop(); | |
| Console.WriteLine(stopwatch.Elapsed.TotalMilliseconds); | |
| stopwatch.Restart(); | |
| for (int i = 0; i < n; i++) | |
| Activator.CreateInstance(typeof(C), args); | |
| stopwatch.Stop(); | |
| Console.WriteLine(stopwatch.Elapsed.TotalMilliseconds / n * 1000); | |
| } | |
| private static void MeasureNew2(int n, int p1, string p2) | |
| { | |
| var stopwatch = Stopwatch.StartNew(); | |
| var c = MyActivator<Func<int, string, C>>.GetDelegate()(p1, p2); | |
| stopwatch.Stop(); | |
| Console.WriteLine(stopwatch.Elapsed.TotalMilliseconds); | |
| stopwatch.Restart(); | |
| for (int i = 0; i < n; i++) | |
| MyActivator<Func<int, string, C>>.GetDelegate()(p1, p2); | |
| stopwatch.Stop(); | |
| Console.WriteLine(stopwatch.Elapsed.TotalMilliseconds / n * 1000); | |
| } | |
| } | |
| // TODO: make thread-safe | |
| static class MyActivator<T> where T : class | |
| { | |
| private static volatile T compiled; | |
| public static T GetDelegate() | |
| { | |
| if (compiled == null) | |
| compiled = CreateCompiledEmit(); | |
| return compiled; | |
| } | |
| private static T CreateCompiledExpression() | |
| { | |
| var invokeMethod = typeof(T).GetMethod("Invoke"); | |
| var ctor = invokeMethod.ReturnType.GetConstructor( | |
| invokeMethod.GetParameters().Select(p => p.ParameterType).ToArray()); | |
| var parameterExpressions = invokeMethod.GetParameters() | |
| .Select(p => Expression.Parameter(p.ParameterType, p.Name)).ToList(); | |
| return Expression.Lambda<T>(Expression.New(ctor, parameterExpressions), parameterExpressions).Compile(); | |
| } | |
| private static T CreateCompiledEmit() | |
| { | |
| var invokeMethod = typeof(T).GetMethod("Invoke"); | |
| var parameterTypes = invokeMethod.GetParameters().Select(p => p.ParameterType).ToArray(); | |
| var ctor = invokeMethod.ReturnType.GetConstructor(parameterTypes); | |
| var method = new DynamicMethod("", invokeMethod.ReturnType, parameterTypes, invokeMethod.ReturnType.Module); | |
| var il = method.GetILGenerator(); | |
| for (int i = 0; i < parameterTypes.Length; i++) | |
| { | |
| il.Emit(OpCodes.Ldarg, i); | |
| } | |
| il.Emit(OpCodes.Newobj, ctor); | |
| il.Emit(OpCodes.Ret); | |
| return (T)(object)method.CreateDelegate(typeof(T)); | |
| } | |
| } | |
| class C | |
| { | |
| public C() | |
| {} | |
| public C(int i, string s) | |
| { | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment