Skip to content

Instantly share code, notes, and snippets.

@svick
Created May 5, 2015 18:46
Show Gist options
  • Select an option

  • Save svick/ebf10598a61a40548325 to your computer and use it in GitHub Desktop.

Select an option

Save svick/ebf10598a61a40548325 to your computer and use it in GitHub Desktop.
Improved Activator
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