【发布时间】:2013-04-07 19:08:05
【问题描述】:
为了避免遇到 X-Y 问题,我想做的是包装 WCF 调用,以便自动实现重试(和其他规则),但我不知道前面的所有接口时间(这是一个中间件)。所以我基本上采用通用DuplexChannelFactory<TChannel>.CreateChannel() 的输出,然后再次使其成为代理。 SO上有几个关于包装调用和重试等的不同问题,但没有一个涉及你需要一个完全通用的解决方案的未知数量的接口。
所以我想在每次客户端调用事物时注入代码,但我希望我的对象直接实现TChannel接口。所以我想使用Reflection.Emit 子类化一个“基础”对象,该对象将保存DuplexChannelFactory<> 调用的结果,然后连接它自己的方法,包括重试功能。这是我在工厂方法中最初的“对象创建”:
static TInterface generateImplementor<TInterface, Tcallback>(params object[] parameters) where TInterface : class
{
// Get the information about the interface. This is necessary because this
// is a generic method, where literally anything could be passed in
Type interfaceType = typeof(TInterface);
// Create the assembly and module to hold the object created
// <snip>
// Define a public class based on the passed-in interface name.
TypeBuilder generatedType = myModule.DefineType(interfaceType.Name + "Implementor",
TypeAttributes.Public, typeof(ForwarderBase<TInterface, Tcallback>),
new Type[] { interfaceType });
// Implement 'TInterface' interface.
generatedType.AddInterfaceImplementation(interfaceType);
好的,但是从那里去哪里呢?这有点像我提出的静态编码,但我需要使用Reflection.Emit 进行最后两个调用。
class ForwarderBase<T, Tcallback>
{
protected T proxyObj;
public ForwarderBase(Tcallback callbackObj)
{
proxyObj = DuplexChannelFactory<T>.CreateChannel(callbackObj, "Endpoint");
}
private void noRetWrapper(Action call)
{
// Inject extra code here possibly
try
{
call();
}
catch (Exception ex)
{
// all of this in a retry loop possibly, or whatever
Console.WriteLine("Exception is: " + ex.ToString());
}
}
private TRet retWrapper<TRet>(Func<TRet> call)
{
// Inject extra code here possibly
try
{
return call();
}
catch (Exception ex)
{
// all of this in a retry loop possibly, or whatever
Console.WriteLine("Exception is: " + ex.ToString());
}
return default(TRet);
}
// Dynamically emit these two, as depending on T, there will be an arbitrary number, with arbitrary arguments
void firstMethod(int x)
{
// Lambda captures the arguments
noRetWrapper(() => proxyObj.noReturnMethodCall(x));
}
int secondMethod(int firstParam, double secondParam, string thirdParam)
{
// Lambda captures the arguments
return retWrapper(() => return proxyObj.returningMethodCall(firstParam, secondParam, thirdParam));
}
}
所以我没有问题Emitting 最后两个方法(以及任何数量的方法,真的应该没问题),除了捕获 lambdas。这是必要的,否则上面的两个“包装器”会爆炸成任意数量的类型和返回值组合。
那么我如何Emit 捕获我需要的 lambda?正如this question 所说,没有Func<...> 之类的,因此我的一个Func 和一个Action 接近这里。
【问题讨论】:
-
我不确定我是否理解你的问题......你不能用 Expression
构建一个表达式树然后调用 CompileToMethod(...) 吗? -
我不熟悉表达式树。有链接吗?还要记住,每个发出的方法上的 lambdas 都会略有不同(调用不同的方法,捕获不同的变量)。如果没问题,那就太好了,但我对表达式树一无所知。
-
您能否添加一个答案 DarkSquirrell42 仅提供如何创建捕获所有参数的表达式树?基本上,如果我需要从我的示例中创建
secondmethod(),我该怎么做?用表达式树做闭包的文档不容易找到。 -
问题是:我不熟悉emit ...我的想法是在生成的类型中引入一个私有成员(成员类型可以由Expression.GetDelegateType()生成)来拥有一个保存你的闭包的字段......闭包本身需要访问实例,因此它不能在创建实例之前创建......这个想法是将该闭包称为某个持有委托的字段,因此可以在实例创建后初始化
标签: c# wcf lambda reflection.emit