如何通过构造函数的args在Activator.CreateInstance或使用IL?函数、args、Activator、CreateInstance

2023-09-02 21:56:16 作者:时光小偷

我需要一个性能增强Activator.CreateInstance()和碰到this由米龙艾布拉姆森使用一个工厂创建于IL实例,然后对其进行缓存文章。 (我已经包含$ C $从米龙艾布拉姆森的网站用户群中不知何故消失低于C)。我是新来的IL的Emit code和超越Activator.CreateInstance()的任何实例化一个类和任何帮助将非常AP preciative。

我的问题是,我需要创建一个对象,它需要一个构造函数带参数的实例。我看到有一个方法来传递参数的类型,但有一种方式来传递在构造函数参数的值呢?

如果可能的话,我想用类似的方法来 CreateObjectFactory< T>(params对象[] constructorParams)一些对象,我要实例可能有不止1构造函数参数。

 
// 资源: http://mironabramson.com/blog/post/2008/08/Fast-version-of-the-ActivatorCreateInstance-method-using-IL.aspx
公共静态类FastObjectFactory
{
    私人静态只读Hashtable的creatorCache = Hashtable.Synchronized(新的Hashtable());
    私人只读静态类型coType = typeof运算(的CreateObject);
    公众委托对象的CreateObject();

    ///
    ///创建一个对象,将作为工厂到指定类型T
   ///
    公共静态的CreateObject CreateObjectFactory()其中T:类
    {
        类型t = typeof运算(T);
        FastObjectFactory.CreateObject C = creatorCache [T]作为FastObjectFactory.CreateObject;
        如果(C == NULL)
        {
            锁定(creatorCache.SyncRoot)
            {
                C = creatorCache [T]作为FastObjectFactory.CreateObject;
                如果(C!= NULL)
                {
                    返回℃;
                }
                DynamicMethod的dynMethod =新的DynamicMethod的(DM $ OBJ_FACTORY_+ t.Name的typeof(对象),空,T);
                的ILGenerator伊尔根= dynMethod.GetILGenerator();

                ilGen.Emit(欧普codes.Newobj,t.GetConstructor(Type.EmptyTypes));
                ilGen.Emit(欧普codes.Ret);
                C =(的CreateObject)dynMethod.CreateDelegate(coType);
                creatorCache.Add(T,C);
            }
        }
        返回℃;
    }
}

 

Update以米龙的$ C $从评论者对他的岗位2010-01-11 ç

 公共静态类FastObjectFactory2< T>其中T:类,新的()
{
    公共静态函数功能< T>的CreateObject {获得;私定; }

    静态FastObjectFactory2()
    {
        输入OBJTYPE = typeof运算(T);
        VAR dynMethod =新的DynamicMethod的(DM $ OBJ_FACTORY_+ objType.Name,OBJTYPE,空,OBJTYPE);
        的ILGenerator伊尔根= dynMethod.GetILGenerator();
        ilGen.Emit(欧普codes.Newobj,objType.GetConstructor(Type.EmptyTypes));
        ilGen.Emit(欧普codes.Ret);
        =的CreateObject(Func键< T>)
        dynMethod.CreateDelegate(typeof运算(Func键< T>));
    }
}
 
成员变量可以在构造函数外调用方法吗,大神们怎么看,我把注释掉的写在构造函数上面怎么不行

解决方案

我至今使用的电流(2010-01-11)答案把这件事作为迄今为止最好的高性能对象创建的工厂,根据我的测试。我也注意到,使用缓存的效果最好迭代下的某处99,999。如果你要加载超过99,999,最好不使用缓存。因为这可能是我创建的东西,可以让你使用缓存或并非如此。我现在的项目有时会加载千万条记录,并在其他时间只加载之一。不管怎么说,我把这个在那里,看看你的想法。请注意,code以下是构造函数的有1阿根廷,人们必须建立一个类似的工厂超过1 ARG构造函数。

 
// code更新2010-06-01
//创建评论的对象类
公共类CreatesSomeObject
{
    //方法是创建一个注释对象
    公共无效CreateComment()
    {

        //方法1(无缓存)
        注释注释1 = ObjectFactoryFactory&ltComment,的ObjectId&GT
            .CreateObject.Invoke(新的ObjectId());

        //方法2(带缓存)
        评论注释2 = ObjectFactoryFactory&ltComment,的ObjectId&GT
            .CreateObjectWithCache.Invoke(新的ObjectId());

        //方法3(不含辅助工厂ObjectFactoryFactory)
        评论comment3 =的ObjectFactory与ltComment,的ObjectId&GT
            .CreateObject.Invoke(新的ObjectId());
    }
}

//这是可选的类。只要有助于创建对象时
//缓存需要或不需要的。
公共静态类ObjectFactoryFactory和LTT,P1&GT其中T:类
{
    静态的Hashtable缓存= Hashtable.Synchronized(新的Hashtable());

    公共静态函数功能及LTP1,T&GT的CreateObject
    {
        {返回的ObjectFactory与LTT,P1和gt.CreateObject; }
    }

    公共静态函数功能及LTP1,T&GT CreateObjectWithCache
    {
        得到
        {
            返回的ObjectFactory与LTT,P1和gt.UseCache(高速缓存);
        }
    }
}

//主要对象的创建工厂类。
公共静态类的ObjectFactory与LTT,P1&GT其中T:类
{

    静态函数功能及LTP1,T&GT _createObject;

    公共静态函数功能及LTP1,T&GT的CreateObject
    {
        得到
        {
            如果(_createObject!= NULL)返回_createObject;
            _createObject = CreateDelegate();
            返回_createObject;
        }
    }

    静态函数功能及LTP1,T&GT CreateDelegate()
    {
        输入OBJTYPE = typeof运算(T);
        键入[]类型=新的[] {typeof运算(P1)};
        VAR dynMethod =新的DynamicMethod的(DM $ OBJ_FACTORY_+
            objType.Name,OBJTYPE,类型,OBJTYPE);
        的ILGenerator伊尔根= dynMethod.GetILGenerator();
        //如果需要超过1 ARG再添Ldarg_x
        //你还需要添加适当的仿制药和
        // CreateDelegate签名
        ilGen.Emit(欧普codes.Ldarg_0);
        ilGen.Emit(欧普codes.Newobj,objType.GetConstructor(类型));
        ilGen.Emit(欧普codes.Ret);
        返程(Func键与LTP1,T&GT)dynMethod.CreateDelegate(typeof运算(Func键与LTP1,T&GT));
    }

    公共静态函数功能及LTP1,T&GT useCache将(哈希表缓存)
    {
        类型t = typeof运算(T);
        Func键与LTP1,T&GT C =缓存[T]作为FUNC&LTP1,T取代;
        如果(C == NULL)
        {
            锁定(cache.SyncRoot)
            {
                C =缓存[T]作为函数功能及LTP1,T取代;
                如果(C!= NULL)
                {
                    返回℃;
                }
                C = CreateDelegate();
                cache.Add(T,C);
            }

        }
        返回℃;
    }
}
 

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. (I've included code below from Miron Abramson's site in case it somehow disappears). I'm new to IL Emit code and anything beyond Activator.CreateInstance() for instantiating a class and any help would be much appreciative.

My problem is that I need to create an instance of an object that takes a ctor with a parameter. I see there is a way to pass in the Type of the parameter, but is there a way to pass in the value of the ctor parameter as well?

If possible, I would like to use a method similar to CreateObjectFactory<T>(params object[] constructorParams) as some objects I want to instantiate may have more than 1 ctor param.


// Source: http://mironabramson.com/blog/post/2008/08/Fast-version-of-the-ActivatorCreateInstance-method-using-IL.aspx
public static class FastObjectFactory
{
    private static readonly Hashtable creatorCache = Hashtable.Synchronized(new Hashtable());
    private readonly static Type coType = typeof(CreateObject);
    public delegate object CreateObject();

    /// 
    /// Create an object that will used as a 'factory' to the specified type T 
   /// 
    public static CreateObject CreateObjectFactory() where T : class
    {
        Type t = typeof(T);
        FastObjectFactory.CreateObject c = creatorCache[t] as FastObjectFactory.CreateObject;
        if (c == null)
        {
            lock (creatorCache.SyncRoot)
            {
                c = creatorCache[t] as FastObjectFactory.CreateObject;
                if (c != null)
                {
                    return c;
                }
                DynamicMethod dynMethod = new DynamicMethod("DM$OBJ_FACTORY_" + t.Name, typeof(object), null, t);
                ILGenerator ilGen = dynMethod.GetILGenerator();

                ilGen.Emit(OpCodes.Newobj, t.GetConstructor(Type.EmptyTypes));
                ilGen.Emit(OpCodes.Ret);
                c = (CreateObject)dynMethod.CreateDelegate(coType);
                creatorCache.Add(t, c);
            }
        }
        return c;
    }
}

Update to Miron's code from commentor on his post 2010-01-11

public static class FastObjectFactory2<T> where T : class, new()
{
    public static Func<T> CreateObject { get; private set; }

    static FastObjectFactory2()
    {
        Type objType = typeof(T);
        var dynMethod = new DynamicMethod("DM$OBJ_FACTORY_" + objType.Name, objType, null, objType);
        ILGenerator ilGen = dynMethod.GetILGenerator();
        ilGen.Emit(OpCodes.Newobj, objType.GetConstructor(Type.EmptyTypes));
        ilGen.Emit(OpCodes.Ret);
        CreateObject = (Func<T>)
        dynMethod.CreateDelegate(typeof(Func<T>));
    }
}

解决方案

I'm putting this up as the so far best performant object creation factory so far using the current (2010-01-11) answers, according to my tests. I did notice that using cache works best when iterations are somewhere below 99,999. If you are going to load more than 99,999 it is best to not use cache. Because this could be the case I've created something that would allow you to use cache or not. My current project will sometimes load millions of records and at other times only load one. Anyways, I'm putting this out there to see what your thoughts are. Note that the code below is for ctor's that have 1 arg, one would have to create a similar factory for more than 1 arg ctor.


// code updated 2010-06-01
// class that creates comment objects
public class CreatesSomeObject
{
    // method that creates a comment object
    public void CreateComment()
    {

        // Method 1 (without cache)
        Comment comment1 = ObjectFactoryFactory<Comment, ObjectId>
            .CreateObject.Invoke(new ObjectId());

        // Method 2 (with cache)
        Comment comment2 = ObjectFactoryFactory<Comment, ObjectId>
            .CreateObjectWithCache.Invoke(new ObjectId());

        // Method 3 (without helper factory ObjectFactoryFactory)
        Comment comment3 = ObjectFactory<Comment, ObjectId>
            .CreateObject.Invoke(new ObjectId());
    }
}

// This is optional class. Just helps in creating objects when
// a cache is needed or not needed.
public static class ObjectFactoryFactory<T, P1> where T : class
{
    static Hashtable cache = Hashtable.Synchronized(new Hashtable());

    public static Func<P1, T> CreateObject
    {
        get { return ObjectFactory<T, P1>.CreateObject; }
    }

    public static Func<P1, T> CreateObjectWithCache
    {
        get
        {
            return ObjectFactory<T, P1>.UseCache(cache);
        }
    }
}

// Main object creation factory class.
public static class ObjectFactory<T, P1> where T : class
{

    static Func<P1, T> _createObject;

    public static Func<P1, T> CreateObject
    {
        get
        {
            if (_createObject != null) return _createObject;
            _createObject = CreateDelegate();
            return _createObject;
        }
    }

    static Func<P1, T> CreateDelegate()
    {
        Type objType = typeof(T);
        Type[] types = new[] { typeof(P1) };
        var dynMethod = new DynamicMethod("DM$OBJ_FACTORY_" + 
            objType.Name, objType, types, objType);
        ILGenerator ilGen = dynMethod.GetILGenerator();
        // if need more than 1 arg add another Ldarg_x
        // you'll also need to add proper generics and 
        // CreateDelegate signatures
        ilGen.Emit(OpCodes.Ldarg_0);
        ilGen.Emit(OpCodes.Newobj, objType.GetConstructor(types));
        ilGen.Emit(OpCodes.Ret);
        return (Func<P1, T>)dynMethod.CreateDelegate(typeof(Func<P1, T>));
    }

    public static Func<P1, T> UseCache(Hashtable cache) 
    { 
        Type t = typeof(T);
        Func<P1, T> c = cache[t] as Func<P1, T>;
        if (c == null) 
        { 
            lock (cache.SyncRoot) 
            {
                c = cache[t] as Func<P1, T>;
                if (c != null) 
                { 
                    return c; 
                } 
                c = CreateDelegate(); 
                cache.Add(t, c); 
            } 

        } 
        return c; 
    }
}