如何在 Activator.CreateInstance 中传递 ctor args 或使用 IL? [英] How to pass ctor args in Activator.CreateInstance or use IL?

查看:16
本文介绍了如何在 Activator.CreateInstance 中传递 ctor args 或使用 IL?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要一个性能增强的 Activator.CreateInstance() 并且遇到了 这篇文章 由 Miron Abramson 撰写,该文章使用工厂在 IL 中创建实例,然后将其缓存.(我在下面包含了来自 Miron Abramson 网站的代码,以防它以某种方式消失).我是 IL Emit 代码的新手,除了 Activator.CreateInstance() 之外的任何用于实例化类的东西,任何帮助都将不胜感激.

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.

我的问题是我需要创建一个对象的实例,该实例采用一个带参数的 ctor.我看到有一种方法可以传入参数的类型,但是有没有方法也可以传入 ctor 参数的值?

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?

如果可能,我想使用类似于 CreateObjectFactory<T>(params object[] constructorParams) 的方法,因为我想实例化的一些对象可能有 1 个以上的 ctor 参数.>

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;
    }
}

更新至Miron 的代码来自评论者在他的帖子 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>));
    }
}

推荐答案

根据我的测试,我使用当前 (2010-01-11) 的答案将其列为迄今为止性能最佳的对象创建工厂.我确实注意到,当迭代次数低于 99,999 时,使用缓存效果最好.如果您要加载超过 99,999 个,最好不要使用缓存.因为这种情况我已经创建了一些允许您使用或不使用缓存的东西.我当前的项目有时会加载数百万条记录,有时只加载一条记录.不管怎样,我把它放在那里看看你的想法.请注意,以下代码适用于具有 1 个 arg 的 ctor,您必须为超过 1 个 arg ctor 创建一个类似的工厂.

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; 
    }
}

这篇关于如何在 Activator.CreateInstance 中传递 ctor args 或使用 IL?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆