使用编译的 Lambda 表达式来初始化 SoapHttpClientProtocol 对象,而不是使用 Activator.CreateInstance。

6

我正在处理一个动态实例化SoapHttpClientProtocol对象(代理类)并使用该对象调用WS-Basic I Web服务的代码。以下是我的代码简化版:

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

我注意到在某些情况下,Activator.CreateInstance()调用可能需要很长时间,因此我正在尝试优化代码,通过使用lambda表达式:不要使用 Activator.CreateInstance 或 ConstructorInfo.Invoke,使用编译的 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); 
}

很遗憾,这段代码并没有创建一个callingObject类型的对象(相反它返回了一个Func<T>委托对象),因此当它尝试在下一行设置Url时会抛出异常:

System.MissingMethodException: 尝试访问一个不存在的成员。

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

谢谢!


链接已经失效了。 - NStuke
2个回答

3

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

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

然而,你正在尝试做的事情在长期运行中似乎相当奇怪和脆弱,因为你正在将方法名称传递为简单字符串,将参数传递为对象,从而失去了所有编译时类型检查。你为什么需要这样做呢?


为什么要使用Delegate并进行动态调用?为什么不直接使用Func然后()呢? - nawfal

0

使用表达式树会导致程序运行速度变慢,除非您缓存已编译的表达式。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接