我正在嘗試優化使用反射創建各種視圖的傳統代碼中類的性能。我寧願我們根本沒有使用反射,但在短期內消除它並不是一種選擇。代碼來自MVC#框架。這裏是:使用反射優化對象創建
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);
}
}
我期待儘快實現這兩種方法。我讀了這個關於對象創建優化的great article by Ayende,並試圖修改他的例子來達到我的目的,但是我對IL的知識並不存在。
我得到一個VerificationException
操作可能會破壞運行時。在Create
方法中。有誰知道這是什麼問題?有沒有更快的實施這種方法我可以使用?這裏是我的嘗試:
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);
}
}
我那麼使用類是這樣的:
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();
}
}
更新1
我做了一些計時:
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
更新2
對於默認的構造函數情況,@Brannon建議的解決方案工作,但獲得的時間是00:00:00.1165000,這並不是一個巨大的改進。那就是:
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();
}
}
更新3
使用的Expression.New
編譯表情也取得了很不錯的成績(00:00:00.1166022)。下面是代碼:
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;
}
}
摘要
對於默認的構造函數的情況下,這裏是概要:
(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
Activator.CreateInstance – hazzik
很好的建議,但仍比使用構造函數慢,但快4倍,比原來的implementaiton –
六次你也應該嘗試'Expression.New':http://geekswithblogs.net/ mrsteve/archive/2012/02/19/a-fast-c-sharp-extension-method-using-expression-trees-create-instance-from-type-again.aspx – YK1