2009-07-01 3 views
2

オープンデリゲート(ターゲットが指定されていないデリゲート)を効率的にクローズドデリゲートに変換する必要があります。私は自分のコードをプロファイリングしており、CreateDelegate()を使用してインスタンスメソッドのクローズドデリゲートを作成するコストは、実行時間全体の60%を超えるかなりの部分を占めています(タイプの新しいインスタンスごとに発生します)。オープンデリゲートとクローズデリゲート間の変換を行う方法

CreateDelegateのドキュメントでは、オープンデリゲートとクローズデリゲートに関する基本情報の一部はdescribed on the MSDN siteです。

私の現在のアプローチは、オープンデリゲートをキャッシュする方法を見つけることです(そのため、作成コストはたった1回しか発生しません)。暗黙の「this」パラメータをデリゲートに提供する別のメソッドを使用して呼び出します。

複雑な要因は、デリゲートがコードのジェネリックパラメータ以外のコンパイル時に表すメソッドのシグネチャがわからないことです。また、パフォーマンスの面で優れているため、反射を避けたい(例:Invoke()DynamicInvoke())。

static TDel CreateOpenDelegate<TDel>(MethodInfo mi) 
{ 
    // creates and returns an open delegate for a delegate of signature TDel 
    // that will invoke some method as described by MethodInfo {mi} 
    return (TDel)(object)Delegate.CreateDelegate(typeof(TDel), mi); 
} 

// simplification of some other code... 
// Note that Action<T> is a sample usage, the actual delegate signature and 
// invocation parameters vary, and are defined by the consumers of my code 
private Action<T> myAction = CreateOpenDelegate<Action<U,T>>(someMethodInfo); 
myAction(this, default(T)); // can't do this since {this} is a hidden parameter... 

私はすでに、私は事前にデリゲートのシグネチャを知らないために、私はそこに記載されているアプローチを適応させる方法が表示されない、残念ながら、Making Reflection Fly and Exploring Delegatesのジョンスキートの記事を読みました。

ご協力いただければ幸いです。

答えて

2

私が正しくあなたの要件を理解していれば、あなたはおそらく、これを達成するために、式ツリーを使用することができます - 私は、トピックhere *を探索ポストを持っています。

public static D GetMethodAccessor<D>(MethodInfo mi) where D : class 
{ 
    Type[] args = typeof(D).GetGenericArguments(); 
    if (args.Length == 0) 
     throw new ArgumentException("Type argument D must be generic."); 

    Type instanceType = args[0]; 

    // If return type is not null, use one less arg 
    bool isAction = mi.ReturnType == typeof(void); 
    int callArgCount = args.Length - (isAction ? 1 : 2); 
    Type[] argTypes = args.Skip(1).Take(callArgCount).ToArray(); 

    var param = Expression.Parameter(instanceType, "obj"); 
    var arguments = argTypes.Select((t, i) => Expression.Parameter(t, "p" + i)) 
          .ToArray(); 
    var invoke = Expression.Call(param, mi, arguments); 
    var lambda = Expression.Lambda<D>(invoke, 
        Enumerable.Repeat(param, 1).Concat(arguments)); 

    Debug.WriteLine(lambda.Body); 
    return lambda.Compile(); 
} 

すべてのことは、追加の型引数の処理と式のコンパイルが、あなたのメソッドとどう比較されるかはわかりません。

暗黙の「this」を提供する限り、拡張メソッドを使用できますか?

private static Action<U,T> myAction = GetMethodAccessor<Action<U,T>>(myMethod); 
public static void MyAction<U,T>(this U u, T t) 
{ 
    myAction(u, t); 
} 

*私はポストに使う文字列ベースのディクショナリ・キャッシュがひどく非効率的であることに注意してください - あなたはあなたの例のようにプライベートインスタンスにデリゲートをキャッシュすることをお勧めします。

0

デリゲートまたはMethodInfoをクローズドデリゲートに変換しようとしていますか?

デリゲートをクローズドデリゲートに変換しようとしている場合は、このようにカリングするのはどうですか?

static Action<T2> Curry<T1, T2>(Action<T1, T2> del, T1 obj) { return p => del(obj, p); } 
+0

残念ながら、私は事前にメソッドシグネチャを知らないので、このようにパラメータを明示的にカレーすることはできません。アクション<>は、自分のコードのコンシューマによって定義された任意のデリゲートにすることができます。 – LBushkin

+0

そうなら、どんなデリゲートタイプにカレーしますか?または、2つのジェネリックパラメータ> – SLaks

関連する問題