简体   繁体   English

使用IL Emit替换Activator.CreateInstance

[英]Using IL Emit to replace Activator.CreateInstance

I have a class implementing an interface, which has a multi-parameter constructor, and a static sorted collection. 我有一个实现接口的类,它有一个多参数构造函数和一个静态排序集合。 This class is a Base Class which has many inherited classes. 此类是一个具有许多继承类的基类。

internal class SCO : IVotable
{
    public SCO(SPListItem item, List<Vote> votes)
    {
        //Initialize Object
    }

    public static List<T> SortedCollection<T>(SPListItemCollection items, ListSortType sortType, List<Vote> votes) where T : IVotable
    {
        var returnlist = new List<T>();
        Type genericType = typeof(T);
        for (int i = 0; i < items.Count; i++) { returnlist.Add((T)Activator.CreateInstance(genericType, new object[] { items[i], votes })); }
        switch (sortType)
        {
            case ListSortType.Hot:
                returnlist.Sort((p1, p2) => p2.HotScore.CompareTo(p1.HotScore));
                break;
            case ListSortType.Top:
                returnlist.Sort((p1, p2) => p2.VoteTotal.CompareTo(p1.VoteTotal));
                break;
            case ListSortType.Recent:
                returnlist.Sort((p1, p2) => p2.CreatedDate.CompareTo(p1.CreatedDate));
                break;
        }
        return returnlist;
    }
}

This allows me to do the following with any Child Class: 这允许我对任何子类进行以下操作:

List<ChildClass> sortedClassList = ChildClass.SortedCollection<ChildClass>(listItems, sortType, votes);

My current reliance on Activator.CreateInstance worries me, as this is about 100 times slower than using Emit IL directly. 我目前对Activator.CreateInstance的依赖让我担心,因为这比直接使用Emit IL慢大约100倍。 I've been reading a few articles about Emit IL, and it seems fantastic for this solution. 我一直在阅读一些关于Emit IL的文章,这个解决方案看起来很棒。

I cannot seem to get it to work, however. 但是,我似乎无法让它工作。 When I try to instantiate ILGenerator gen = it tells me "Cannot access non-static field 'method' in static context" 当我尝试实例化ILGenerator gen =它告诉我“无法在静态上下文中访问非静态字段'方法”

My class isn't static, neither are my constructors, and the static list show below isn't interacting with Emit yet. 我的类不是静态的,也不是我的构造函数,下面显示的静态列表还没有与Emit交互。 How do I make this work? 我该如何工作?

Code thus far: 代码到目前为止:

internal class SCO : IVotable
{
    //Properties emittied
    static ConstructorInfo ctor = typeof(SCO).GetConstructors()[1];
    delegate SCO SCOCtor(SPListItem item, List<Vote> votes);
    static SCOCtor SCOCtorDelegate;

    DynamicMethod method = new DynamicMethod("CreateInstance", typeof (SCO),
                             new Type[] {typeof (SPListItem), typeof (List<Vote>)});

    ILGenerator gen = method.GetILGenerator(); //Error here
    //"Cannot access non-static field 'method' in static context"

    private static SCO CreateInstance(SPListItem item, List<Vote> votes)
    {
        return SCOCtorDelegate(item, votes);
    }
}

Blog for reference: http://ayende.com/blog/3167/creating-objects-perf-implications 博客供参考: http//ayende.com/blog/3167/creating-objects-perf-implications

I have a drop-in replacement for Activator that uses IL generation hosted here on CodePlex. 我有激活剂直接替代使用IL代托管在这里在CodePlex上。 You can also get it via Nuget here (a single source file include, no assemblies). 你也可以通过Nuget 在这里获得它(单个源文件包括,没有程序集)。

The source code for FasterActivator is here . FasterActivator的源代码在这里

Usage is something like what's outlined below. 用法类似于下面概述的内容。

private static readonly Dictionary<Type, DynamicCreationDelegate> _cachedCreationDelegates = new Dictionary<Type, DynamicCreationDelegate>();

private static DynamicCreationDelegate CreateOrGet(Type typeToCreate)
{
    DynamicCreationDelegate result = null;

    if (!_cachedCreationDelegates.TryGetValue(typeToCreate, out result))
    {
        result = FastActivator.GenerateDelegate(typeToCreate, 
        /* List of types that make up the constructor signature of the type being constructed */
        typeof(SPListItem), typeof(List<Vote>));
        _cachedCreationDelegates.Add(result);
    }

    return result;
}

// Usage 
for (int i = 0; i < items.Count; i++) 
{ 
    var creationDelegate = CreateOrGet(typeof(genericType));
    returnlist.Add((T)creationDelegate(new object[] { items[i], votes })); 
}

Oh, and here is a generic version that ought to be faster. 哦,这是一个应该更快的通用版本。

private static readonly Func<SPListItem, List<T>, T> _creationFunc;
private static Func<SPListItem, List<T>, T> CreateOrGetFunc()
{
    if (!_creationFunc == null)
        _creationFunc = FastActivator.GenerateFunc<Func<SPListItem, List<T>, T>>(/* IL generator knows all type info from generic params now */);

    return _creationFunc;
}

// Usage
for (int i = 0; i < items.Count; i++) 
{ 
    var creationFunc = CreateOrGetFunc();
    returnlist.Add(creationFunc(items[i], votes )); 
}

Hope this helps! 希望这可以帮助!

I see you've got a answer. 我看到你有一个答案。 I just uploaded to github the code of a helper class to IL constructor calls (I was supposed to have done this before, but were missing a good reason ): 我刚刚向github上传了一个辅助类的代码到IL构造函数调用(我本来应该这样做过,但是错过了一个很好的理由):

The usage is something like this: 用法是这样的:

// suppose you want to call the constructor for this class  
// but generalizing the return to ISomeInterface
public class AClass : ISomeInterface
{
   public class(int intParam, String stringParam) { }
}

// construct the factory method Func<int, string, ISomeInterface>
var createAClassInstance = ReflectionHelper
   // return type + constructor params
   .CreateFactoryMethod<ISomeInterface, int, string>(typeof(AClass));

var instance = createAClassInstance(10, "hello constructor");

If you're willing to accept some repetition, then instead of dealing with IL (which can get complicated fast, as you discovered), you can use delegates. 如果你愿意接受一些重复,那么你可以使用代理,而不是处理IL(它可以快速复杂,如你所发现的那样)。 Something like: 就像是:

internal class SCO : IVotable
{
    protected static List<T> SortedCollection<T>
        (SPListItemCollection items, ListSortType sortType, List<Vote> votes,
        Func<SPListItem, List<Vote>, T> factory) where T : IVotable
    {
        var returnlist = new List<T>();
        Type genericType = typeof(T);
        for (int i = 0; i < items.Count; i++)
            returnlist.Add(factory(items[i], votes));

        // etc.
    }
}

class ChildClass : SCO
{
    public static List<ChildClass> SortedCollection
        (SPListItemCollection items, ListSortType sortType, List<Vote> votes)
    {
        return SCO.SortedCollection<ChildClass>(
            items, sortType, votes, (i, vs) => new ChildClass(i, vs));
    }
}

Doing it this way should be very fast, probably even slightly faster than when using IL emit. 这样做应该非常快,甚至可能比使用IL发射时稍快。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM