使用Compiled Lambda表达式而不是Activator.CreateInstance来初始化SoapHttpClientProtocol对象

Mis*_*sky 6 c# linq reflection activator expression-trees

我正在使用动态实例化SoapHttpClientProtocol对象(代理类)的代码,并使用此对象来调用WS-Basic I Web Service.这是我的代码的简化版本:

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); 
}
Run Code Online (Sandbox Code Playgroud)

我注意到在某些情况下Activator.CreateInstance()调用会花费大量时间,所以我试图通过使用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); 
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,这段代码不会创建该callingObject类型的对象(而是返回一个Func<T>委托对象),因此当它尝试Url在下一行中设置它时会引发异常:

System.MissingMethodException:尝试访问缺少的成员.

我在代码中遗漏了什么吗?

谢谢!

Nik*_*sev 3

Expression.Lambda(Expression.New(constructorInfo)).Compile()部分返回一个委托,该委托包装了存储在参数中Func<T>的构造函数。要实际调用该构造函数,您仍然需要调用它:TypecallingObject

Delegate delegateWithConstructor = Expression.Lambda(Expression.New(constructorInfo)).Compile();
object instance = delegateWithConstructor.DynamicInvoke();
Run Code Online (Sandbox Code Playgroud)

然而,从长远来看,您尝试做的事情似乎非常奇怪和脆弱,因为您将方法名称作为简单字符串和参数作为对象传递,因此丢失了所有编译时类型检查。为什么你需要这样做?