2 Stimmen

Eine Möglichkeit, zwischen offenen und geschlossenen Delegierten zu konvertieren

Ich muss einen offenen Delegaten (bei dem das Ziel nicht angegeben ist) effizient in einen geschlossenen Delegaten umwandeln. Ich habe meinen Code profiliert, und die Kosten für die Verwendung von CreateDelegate() um einen geschlossenen Delegaten für eine Instanzmethode zu erzeugen, macht einen beträchtlichen Teil (>60%) der Gesamtlaufzeit aus (da dies für jede neue Instanz des Typs geschieht).

Einige grundlegende Informationen über offene und geschlossene Delegierte sind beschrieben auf der MSDN-Website in der Dokumentation für CreateDelegate .

Mein derzeitiger Ansatz ist es, einen Weg zu finden, um den offenen Delegaten zwischenzuspeichern (so dass die Kosten für die Erstellung es nur einmal angefallen ist) und rufen Sie es mit einer anderen Methode, die die implizite "this" Parameter an den Delegaten liefert.

Ein komplizierender Faktor ist, dass ich die Signatur der Methode nicht kenne, die der Delegat zur Kompilierungszeit darstellen wird, außer durch einen generischen Parameter im Code. Darüber hinaus möchte ich Reflexion vermeiden (z.B. Invoke() y DynamicInvoke() ), da sie in Bezug auf die Leistung nicht besser sind.

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...

Ich habe bereits den Artikel von Jon Skeet über Reflexion zum Fliegen bringen und Delegierte erforschen Da ich die Delegatensignatur nicht im Voraus kenne, sehe ich leider keine Möglichkeit, den dort beschriebenen Ansatz anzupassen.

Für jede Hilfe wären wir dankbar.

2voto

dahlbyk Punkte 71222

Wenn ich Ihre Anforderungen richtig verstehe, könnten Sie wahrscheinlich Ausdrucksbäume verwenden, um dies zu erreichen - ich habe einen Beitrag, der das Thema untersucht aquí *. Hier ist eine vereinfachte Version:

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

Allerdings bin ich mir nicht sicher, wie die zusätzliche Verarbeitung von Typargumenten und die Kompilierung von Ausdrücken im Vergleich zu Ihrer Methode aussehen würde.

So weit wie die Bereitstellung der impliziten "this", könnte die Verwendung von Erweiterungsmethoden?

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

*Beachten Sie, dass der String-basierte Wörterbuch-Cache, den ich im Beitrag verwende, furchtbar ineffizient ist - Sie möchten den Delegaten in einer privaten Instanz wie in Ihrem Beispiel zwischenspeichern.

0voto

SLaks Punkte 832502

Versuchen Sie, einen Delegierten oder eine MethodInfo an einen geschlossenen Delegierten?

Wenn Sie versuchen, einen Delegaten in einen geschlossenen Delegaten zu konvertieren, wie wäre es mit Currying, etwa so?

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X