How to pass ctor args in Activator.CreateInstance or use IL?

后端 未结 8 1747
野的像风
野的像风 2020-12-07 16:06

I need a performance enhanced Activator.CreateInstance() and came across this article by Miron Abramson that uses a factory to create the instance in IL and then cache it. (

8条回答
  •  一整个雨季
    2020-12-07 16:41

    I had no idea that new T() was slow in a generic class. My problem is really something else though - if I knew what T was at compile time I'd be fine but I want a quick way to instantiate a class specified by configuration information (i.e. strings holding assembly / class names) at runtime. I use a cache of Type objects to load the assembly and locate the type in it only once, so the last hurdle is to quickly create instances, which was the subject of my previous post.

    Anyhow, following from my finding that .NET 4.0 is quicker at this sort of thing I tested with a version of your example, calling each CreateNewInstxxx method 1,000,000 times. Timings in milliseconds:

    class GenericClass where T : new()
    {
        Func ClassFactory;    
        public GenericClass(Func classFactory)    
        {        
            this.ClassFactory = classFactory;    
        }    
        public T CreateNewInstQuick()    
        {        
            return ClassFactory(); // Calls the quick IL mnemonic 'newobj'   
        }
        public T CreateNewInstStd()
        {
            return new T(); // <- calls the slow Activator.CreateInstance() in IL
        }
    }
    
    .NET 3.5
    CreateNewInstQuick: 35
    CreateNewInstStd: 1298
    
    .NET 4.0
    CreateNewInstQuick: 29
    CreateNewInstStd: 165
    

    So yes, .NET 4.0 is much faster than previously here too. The code generated by the compiler for the CreateNewInstStd() method looks like this in both cases so it seems the speedup is down to the improved Activator.CreateInstance() method:

    public T CreateNewInstStd()
    {
        T t1 = default(T);
        if (t1 != null)
        {
            T t2 = default(T);
            return t2;
        }
        return Activator.CreateInstance();
    }
    

    Edit: To add that performance is roughly the same when the GenericClass is constrained to reference types via this:

    class GenericClass where T :  class, new()
    

    and in that case the compiler-generated code is then just this:

    public T CreateNewInstStd()
    {
        return Activator.CreateInstance();
    }
    

提交回复
热议问题