Verwenden Sie den Compiled Lambda-Ausdruck anstelle von Activator.CreateInstance, um das SoapHttpClientProtocol-Objekt zu initialisieren

activator c# expression-trees linq reflection

Frage

Ich arbeite mit dem Code, der das SoapHttpClientProtocol Objekt (Proxy-Klasse) dynamisch instanziiert und dieses Objekt verwendet, um einen Aufruf an WS-Basic I Web Service zu SoapHttpClientProtocol . Hier ist die vereinfachte Version meines Codes:

public override object Call(Type callingObject,
string method, object[] methodParams, string URL)
{
    MethodInfo requestMethod = callingObject.GetMethod(method);

    //creates an instance of SoapHttpClientProtocol
    object instance = Activator.CreateInstance(callingObject);

    //sets the URL for the object that was just created 
    instance.GetType().InvokeMember("Url", 
    BindingFlags.Public | BindingFlags.Instance | BindingFlags.SetProperty, null,
    instance,
    new object[1] {URL});

    return requestMethod.Invoke(instance, methodParams); 
}

Ich habe festgestellt, dass der Aufruf von Activator.CreateInstance() in einigen Fällen viel Zeit in Activator.CreateInstance() nehmen kann. Daher versuche ich, den Code mithilfe eines Lambda-Ausdrucks zu optimieren:

public override object Call(Type callingObject,
string method, object[] methodParams, string URL)
{
    MethodInfo requestMethod = callingObject.GetMethod(method);

    //creates an instance of SoapHttpClientProtocol using compiled Lambda Expression
    ConstructorInfo constructorInfo = callingObject.GetConstructor(new Type[0]);
    object instance = Expression.Lambda(Expression.New(constructorInfo)).Compile();

    //sets the URL for the object that was just created 
    instance.GetType().InvokeMember("Url", 
    BindingFlags.Public | BindingFlags.Instance | BindingFlags.SetProperty, null,
    instance,
    new object[1] {URL});

    //calls the web service
    return requestMethod.Invoke(instance, methodParams); 
}

Leider erzeugt dieser Code kein Objekt vom Typ callingObject (stattdessen gibt es ein Func<T> ), und daher wird beim Versuch, die Url in der nächsten Zeile zu setzen, eine Ausnahme Func<T> :

System.MissingMethodException: Es wurde versucht, auf ein fehlendes Mitglied zuzugreifen.

Fehle ich etwas in meinem Code?

Vielen Dank!

Akzeptierte Antwort

Der Expression.Lambda(Expression.New(constructorInfo)).Compile() gibt einen Func<T> , der einen Konstruktor von Type umhüllt, der in callingObject Parameter callingObject gespeichert ist. Um diesen Konstruktor tatsächlich aufzurufen , müssen Sie ihn noch aufrufen:

Delegate delegateWithConstructor = Expression.Lambda(Expression.New(constructorInfo)).Compile();
object instance = delegateWithConstructor.DynamicInvoke();

Was Sie zu tun versuchen, scheint auf lange Sicht jedoch merkwürdig und fragil zu sein, da Sie Methodennamen als einfache Strings und Parameter als Objekte weitergeben und somit die Kompilierzeit-Typprüfung verlieren. Warum musst du es tun?


Beliebte Antwort

Wenn Sie Ausdrucksbäume verwenden, wird Ihr Programm langsamer ausgeführt, wenn Sie den kompilierten Ausdruck nicht zwischenspeichern.



Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow