Use la expresión Lambda compilada en lugar de Activator.CreateInstance para inicializar el objeto SoapHttpClientProtocol

activator c# expression-trees linq reflection

Pregunta

Estoy trabajando con el código que SoapHttpClientProtocol instancia dinámica del objeto SoapHttpClientProtocol (clase proxy) y utiliza este objeto para realizar una llamada al servicio web WS-Basic I. Aquí está la versión simplificada de mi código:

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

Me he dado cuenta de que, en algunos casos, la llamada a Activator.CreateInstance() puede llevar una cantidad de tiempo considerable, por lo que estoy tratando de optimizar el código usando una expresión lambda :

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

Desafortunadamente, este código no crea un objeto del tipo callingObject (en su lugar, devuelve un objeto delegado Func<T> ) y, por lo tanto, cuando intenta establecer la Url en la siguiente línea, lanza una excepción:

System.MissingMethodException: se intentó acceder a un miembro faltante.

¿Me falta algo en mi código?

¡Gracias!

Respuesta aceptada

La parte Expression.Lambda(Expression.New(constructorInfo)).Compile() devuelve un delegado Func<T> que envuelve un constructor de Type almacenado en el parámetro callingObject . Para llamar a ese constructor, necesitas invocarlo:

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

Sin embargo, lo que está intentando hacer parece bastante extraño y frágil a largo plazo, ya que pasa los nombres de los métodos como cadenas y parámetros simples como objetos, por lo que pierde toda la verificación de tipos en tiempo de compilación. ¿Por qué necesitas hacerlo?


Respuesta popular

El uso de árboles de expresiones hará que su programa se ejecute más lento a menos que almacene en caché la expresión compilada.



Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow