【发布时间】:2014-04-07 08:30:19
【问题描述】:
我正在尝试优化我们遗留代码中使用反射来创建各种视图的类的性能。我宁愿我们根本不使用反射,但在短期内移除它不是一种选择。代码来自 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.0225015 -
Activator.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.3946555 -
new Created(): 00:00:00.0225015 -
Activator.CreateInstance<Created>(): 00:00:00.1232143 -
DynamicMethod: 00:00:00.1165000 -
Expression.New: 00:00:00.1131143
【问题讨论】:
-
Activator.CreateInstance
-
好建议,它仍然比使用构造函数慢 6 倍,但比原始实现快 4 倍
-
你也应该试试
Expression.New:geekswithblogs.net/mrsteve/archive/2012/02/19/…
标签: c# optimization reflection