Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use Compiled Lambda expression instead of Activator.CreateInstance to initialize SoapHttpClientProtocol object

I'm working with the code that dynamically instantiates SoapHttpClientProtocol object (proxy class) and uses this object to make a call to WS-Basic I Web Service. Here is the simplified version of my code:

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

I've noticed that in some cases Activator.CreateInstance() call can take significant amount of time, so I'm trying to optimize the code 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); 
}

Unfortunately, this code does not create an object of the callingObject type (instead it returns a Func<T> delegate object) and therefore when it tries to set the Url in the next line it throws an exception:

System.MissingMethodException: Attempted to access a missing member.

Am I missing something in my code?

Thanks!

like image 889
Misha Narinsky Avatar asked Jul 26 '12 17:07

Misha Narinsky


1 Answers

The Expression.Lambda(Expression.New(constructorInfo)).Compile() part returns a Func<T> delegate that wraps a constructor of Type stored in callingObject parameter. To actually call that constructor, you still need to invoke it:

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

However, what you are trying to do seems quite strange and fragile in the long run, since you are passing around method names as simple strings and parameters as objects, therefore losing all compile-time type checking. Why do you need to do it?

like image 132
Nikola Anusev Avatar answered Sep 29 '22 05:09

Nikola Anusev