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

I work with code that dynamically creates an instance of the SoapHttpClientProtocol object (proxy class) and uses this object to call WS-Basic I Web Service. Here is a 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 noticed that in some cases, calling Activator.CreateInstance() can take a considerable amount of time, so I'm trying to optimize the code 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 type callingObject (instead, it returns a delegate object Func<T> ), and therefore, when it tries to set Url in the next line, it throws an exception:

System.MissingMethodException: Attempted to access a missing item.

Am I missing something in my code?

Thanks!

+6
source share
2 answers

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

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

However, what you are trying to do seems rather strange and fragile in the long run, because you pass method names as simple strings and parameters as objects, so you lose all compilation type checking. Why do you need this?

+3
source

Using expression trees will cause your program to run slowly if you do not compile the compiled expression.

0
source

Source: https://habr.com/ru/post/921422/


All Articles