1

複数パラメーターのコンストラクターと静的な並べ替えられたコレクションを持つインターフェイスを実装するクラスがあります。このクラスは、多くの継承クラスを持つ基本クラスです。

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

これにより、任意の子クラスで次のことができます。

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

現在 Activator.CreateInstance に依存していることは心配です。Emit IL を直接使用するよりも約 100 倍遅いからです。Emit IL に関するいくつかの記事を読んでいますが、このソリューションは素晴らしいと思います。

しかし、私はそれを機能させることができないようです。インスタンス化しようとすると、ILGenerator gen =「静的コンテキストで非静的フィールド 'メソッド' にアクセスできません」と表示されます。

私のクラスもコンストラクターも静的ではありません。以下に示す静的リストはまだ Emit とやり取りしていません。どうすればこれを機能させることができますか?

これまでのコード:

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

参考ブログ: http://ayende.com/blog/3167/creating-objects-perf-implications

4

3 に答える 3

2

ここCodePlex でホストされている IL 生成を使用する Activator のドロップイン代替品があります。こちらから Nuget 経由で入手することもできます(単一のソース ファイルが含まれ、アセンブリは含まれません)。

FasterActivator のソース コードはこちらです。

使用法は、以下に概説するようなものです。

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

ああ、これはより高速な一般的なバージョンです。

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

お役に立てれば!

于 2012-08-27T18:13:06.437 に答える
1

私はあなたが答えを持っていることを参照してください。ILコンストラクター呼び出しのヘルパークラスのコードをgithubにアップロードしました(以前にこれを行うはずでしたが、正当な理由がありませんでした):

使用法は次のようなものです。

// 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");
于 2012-08-27T21:13:05.600 に答える
1

いくらかの繰り返しを受け入れたい場合は、IL を処理する代わりに (おわかりのように、すぐに複雑になる可能性があります)、デリゲートを使用できます。何かのようなもの:

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

このようにすると非常に速くなり、おそらく IL を使用した場合よりもわずかに速くなります。

于 2012-08-28T08:29:47.380 に答える