2014-04-02 71 views
2

我正在尝试优化使用反射创建各种视图的传统代码中类的性能。我宁愿我们根本没有使用反射,但在短期内消除它并不是一种选择。代码来自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.3946555

  • new 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
+0

Activator.CreateInstance – hazzik

+0

很好的建议,但仍比使用构造函数慢,但快4倍,比原来的implementaiton –

+0

六次你也应该尝试'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

回答

1

首先,你应该禁用特定测试的垃圾收集器。这可能会妨碍你的结果。或者你可以把所有创建的实例放入一个数组中。我不知道作为它的一部分调用ToString()也有帮助。

您对花式构造函数代码的计划不一定是正确的计划。构造函数查找本身很慢。您应该使用Type密钥将代表缓存在字典中。大多数IoC容器会自动为您执行此操作(缓存和构建)。我认为使用其中之一在您的情况下将证明是有价值的。实际上,较新的JSON框架还会缓存构造函数信息以快速创建对象。也许类似Json.Net或ServiceStack.Text会有所帮助。

您构建了多少种不同的类型? (我知道你的例子只显示一个。)

我不确定你的DynamicMethod参数是否正确。这个代码(下面)对我来说一直很稳定。不要在值类型或数组上调用它。

DynamicMethod dm = new DynamicMethod("MyCtor", type, Type.EmptyTypes, typeof(ClassFactory).Module, true); 
ILGenerator ilgen = dm.GetILGenerator(); 
ilgen.Emit(OpCodes.Nop); 
ilgen.Emit(OpCodes.Newobj, ci); 
ilgen.Emit(OpCodes.Ret); 
CtorDelegate del = ((CtorDelegate) dm.CreateDelegate(typeof(CtorDelegate))); 
return del.Invoke(); // could cache del in a dictionary 
+0

+1谢谢你的回答,我会尝试你的代码并将构造函数委托存储在字典中。我们可能创造了大约50种不同的类型。 –

+0

您发布的代码工作得很好,谢谢!你有没有机会知道如何为非默认构造函数生成IL? –

+0

我不知道其他构造函数的IL。对于他们,你可以尝试缓存编译的表达式。看到这里:http://rogeralsing.com/2008/02/28/linq-expressions-creating-objects/ – Brannon