I am trying to optimize the performance of a class in our legacy code that is using reflection to create various views. I'd rather we didn't use reflection at all, but removing it is not an option in the short term. The code comes from the MVC# framework. Here it is:
public class CreateHelper
{
#region Documentation
/// <summary>
/// Creates an object of specified type.
/// </summary>
#endregion
public static object Create(Type t)
{
return t.GetConstructor(new Type[] { }).Invoke(new object[] { });
}
#region Documentation
/// <summary>
/// Creates an object of specified type with parameters passed to the constructor.
/// </summary>
#endregion
public static object Create(Type t, params object[] parameters)
{
Type[] paramTypes = new Type[parameters.Length];
for (int i = 0; i < parameters.Length; i++)
paramTypes[i] = parameters[i].GetType();
return t.GetConstructor(paramTypes).Invoke(parameters);
}
}
I am looking to make the implementation of these two methods as fast as possible. I read this great article by Ayende on object creation optimization and have tried to modify his example for my purposes, however my knowledge of IL is non existent.
I get a VerificationException Operation could destabilize the runtime. in the Create method. Does anyone know what is the problem? Is there a faster implementation of this method I can use? Here is my attempt:
public class Created
{
public int Num;
public string Name;
public Created()
{
}
public Created(int num, string name)
{
this.Num = num;
this.Name = name;
}
}
public class CreateHelper
{
private delegate object CreateCtor();
private static CreateCtor createdCtorDelegate;
#region Documentation
/// <summary>
/// Creates an object of specified type.
/// </summary>
#endregion
public static object Create(Type t)
{
var ctor = t.GetConstructor(new Type[] { });
var method = new DynamicMethod("CreateIntance", t, new Type[] { typeof(object[]) });
var gen = method.GetILGenerator();
gen.Emit(OpCodes.Ldarg_0);//arr
gen.Emit(OpCodes.Call, ctor);// new Created
gen.Emit(OpCodes.Ret);
createdCtorDelegate = (CreateCtor)method.CreateDelegate(typeof(CreateCtor));
return createdCtorDelegate(); // <=== VerificationException Operation could destabilize the runtime.
}
#region Documentation
/// <summary>
/// Creates an object of specified type with parameters passed to the constructor.
/// </summary>
#endregion
public static object Create(Type t, params object[] parameters)
{
Type[] paramTypes = new Type[parameters.Length];
for (int i = 0; i < parameters.Length; i++)
paramTypes[i] = parameters[i].GetType();
return t.GetConstructor(paramTypes).Invoke(parameters);
}
}
I then use the class like this:
class Program
{
private static Created CreateInstance()
{
return (Created)CreateHelper.Create(typeof(Created));
//return new Created();
}
static void Main(string[] args)
{
int iterations = 1000000;
Stopwatch watch = Stopwatch.StartNew();
for (int i = 0; i < iterations; i++)
{
CreateInstance();
}
Console.WriteLine(watch.Elapsed);
Console.ReadLine();
}
}
Update 1
I did some timings:
new Created(): 00:00:00.0225015Activator.CreateInstance<Created>(): 00:00:00.1232143(Created)CreateHelper.Create(typeof(Created)): 00:00:00.3946555new Created(i, i.ToString()): 00:00:00.1476882(Created)Activator.CreateInstance(typeof(Created), new object[]{ i, i.ToString() }): 00:00:01.6342624(Created)CreateHelper.Create(typeof(Created), new object[] {i, i.ToString()}): 00:00:01.1591511
Update 2
For the default constructor case, the solution suggested by @Brannon worked, however the time obtained was 00:00:00.1165000, which was not a huge improvement. Here it is:
public class CreateHelper
{
private delegate object DefaultConstructor();
private static readonly ConcurrentDictionary<Type, DefaultConstructor> DefaultConstructors = new ConcurrentDictionary<Type, DefaultConstructor>();
#region Documentation
/// <summary>
/// Creates an object of specified type.
/// </summary>
#endregion
public static object Create(Type t)
{
DefaultConstructor defaultConstructorDelegate;
if (!DefaultConstructors.TryGetValue(t, out defaultConstructorDelegate))
{
var ctor = t.GetConstructor(Type.EmptyTypes);
var method = new DynamicMethod("CreateIntance", t, Type.EmptyTypes);
var gen = method.GetILGenerator();
gen.Emit(OpCodes.Nop);
gen.Emit(OpCodes.Newobj, ctor);
gen.Emit(OpCodes.Ret);
defaultConstructorDelegate = (DefaultConstructor)method.CreateDelegate(typeof(DefaultConstructor));
DefaultConstructors[t] = defaultConstructorDelegate;
}
return defaultConstructorDelegate.Invoke();
}
}
Update 3
Using a compiled expression of Expression.New also yielded a very good result (00:00:00.1166022). Here is the code:
public class CreateHelper
{
private static readonly ConcurrentDictionary<Type, Func<object>> DefaultConstructors = new ConcurrentDictionary<Type, Func<object>>();
#region Documentation
/// <summary>
/// Creates an object of specified type.
/// </summary>
#endregion
public static object Create(Type t)
{
Func<object> defaultConstructor;
if (!DefaultConstructors.TryGetValue(t, out defaultConstructor))
{
var ctor = t.GetConstructor(Type.EmptyTypes);
if (ctor == null)
{
throw new ArgumentException("Unsupported constructor for type " + t);
}
var constructorExpression = Expression.New(ctor);
var lambda = Expression.Lambda<Func<Created>>(constructorExpression);
defaultConstructor = lambda.Compile();
DefaultConstructors[t] = defaultConstructor;
}
return defaultConstructor.Invoke();
}
#region Documentation
/// <summary>
/// Creates an object of specified type with parameters passed to the constructor.
/// </summary>
#endregion
public static object Create(Type t, params object[] parameters)
{
return null;
}
}
Summary
For the default constructor case, here is the summary:
(Created)CreateHelper.Create(typeof(Created)): 00:00:00.3946555new Created(): 00:00:00.0225015Activator.CreateInstance<Created>(): 00:00:00.1232143DynamicMethod: 00:00:00.1165000Expression.New: 00:00:00.1131143
Expression.New: geekswithblogs.net/mrsteve/archive/2012/02/19/…