2012-07-26 22 views
5

Pracuję z kodem, który dynamicznie tworzy instancję obiektu SoapHttpClientProtocol (klasa proxy) i używa tego obiektu do wykonania wywołania usługi WS-Basic I Web Service. Oto uproszczona wersja mojego kodu:Użyj skompilowanego wyrażenia Lambda zamiast Activator.CreateInstance, aby zainicjować obiekt SoapHttpClientProtocol

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

Zauważyłem, że w niektórych przypadkach Activator.CreateInstance() wezwanie może mieć znaczną ilość czasu, więc staram się zoptymalizować kod by using a lambda expression:

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

Niestety, ten kod nie tworzy obiektu typu callingObject (zamiast tego zwraca obiekt delegowany Func<T>) i dlatego, gdy próbuje ustawić Url w następnej linii, zgłasza wyjątek:

System.MissingMethodException: Próba dostępu do brakującego elementu.

Czy brakuje mi czegoś w moim kodzie?

Dzięki!

+0

Link jest martwy przy okazji. – NStuke

Odpowiedz

3

Część zwraca delegata Func<T>, który otacza konstruktora o wartości Type przechowywany w parametrze callingObject. Faktycznie wezwanie że konstruktor, trzeba jeszcze, aby go wywołać:

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

Jednak to, co staramy się robić wydaje się dość dziwny i kruchy w dłuższej perspektywie, ponieważ są przechodzącą wokół nazwy metody jako prostych ciągów i parametry jako obiekty, tracąc w ten sposób całe sprawdzanie typu kompilacji. Dlaczego musisz to robić?

+0

+1, krótki i prosty. Ale dlaczego wziąć "Delegata" z powrotem i wykonać dynamiczne wywoływanie? Dlaczego nie po prostu 'Func', a następnie()? – nawfal

0

Używanie drzewek wyrażeń spowoduje, że program będzie działał wolniej, chyba że buforujesz skompresowane wyrażenie.