我正在尝试围绕由接口定义的服务创建代理包装器,以向服务的开发人员用户“隐藏”客户端特定的调用代码。
我已经能够生成大部分包装类本身,但现在正在努力为预先存在的客户端调用生成 Func 参数。
一个示例 TService 有一个接口:
public interface ITestService
{
public Task ServiceMethodAsync();
public Task<TestDTO> ServiceMethodWithResultAsync();
}
客户端实现的签名是:
public Task<TResult> CallAsync<TResult>(Func<TService, Task<TResult>> operation);
public Task CallAsync(Func<TService, Task> operation);
直接调用时,开发人员当前会写如下内容:
var result = await client.CallAsync(service => service.ServiceMethodWithResultAsync(requestDTO));
虽然首选的选项是他们可以调用:
var result = await service.ServiceMethodWithResultAsync(requestDTO);
因为这允许 DI 使用 IService 接口注入本地服务或我的远程包装器,并且开发人员不需要考虑它是远程服务还是本地服务。
我目前让我的 typebuilder 生成所需的代码来创建从客户端继承的包装类baseType
并针对它定义所有接口方法,但目前将 null 作为Func<TService, Task<TResult>> operation
.
private static void DefineInterface(TypeBuilder typeBuilder, Type baseType, Type serviceInterfaceType)
{
foreach (MethodInfo serviceMethod in serviceInterfaceType.GetMethods())
{
ParameterInfo[] parameters = serviceMethod.GetParameters();
MethodBuilder methodBuilder = typeBuilder.DefineMethod(
serviceMethod.Name,
serviceMethod.Attributes ^ MethodAttributes.Abstract,
serviceMethod.CallingConvention,
serviceMethod.ReturnType,
serviceMethod.ReturnParameter.GetRequiredCustomModifiers(),
serviceMethod.ReturnParameter.GetOptionalCustomModifiers(),
parameters.Select(p => p.ParameterType).ToArray(),
parameters.Select(p => p.GetRequiredCustomModifiers()).ToArray(),
parameters.Select(p => p.GetOptionalCustomModifiers()).ToArray());
ILGenerator ilGenerator = methodBuilder.GetILGenerator();
MethodInfo callAsyncMethod = getCallAsyncMethod(baseType, serviceMethod);
ilGenerator.Emit(OpCodes.Ldarg_0); // Push "this"
ilGenerator.Emit(OpCodes.Ldnull); // Push Func<> argument
ilGenerator.Emit(OpCodes.Call, callAsyncMethod); // Call CallAsync on the base client
ilGenerator.Emit(OpCodes.Ret);
}
}
从这里我有点坚持到底如何定义 Func<>service => service.ServiceMethodWithResultAsync(requestDTO)
包括requestDTO
我期望/假设的参数Ldarg_1
等Ldarg_2
?
非常感谢任何和所有帮助。