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!
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?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With