Я пытаюсь создать прокси-оболочку для сервисов, которые определяются интерфейсом, чтобы «скрыть» клиентский указанный c код вызова от пользователя-разработчика сервиса.
Я уже смог для создания большей части самого класса-оболочки, но сейчас я пытаюсь сгенерировать аргумент Fun c для уже существующего клиентского вызова.
Пример 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, а также то, является ли это удаленным сервисом или локальным сервисом, разработчик не должен учитывать.
В настоящее время мой типообразователь генерирует необходимый код для создания класса-оболочки, наследуемого от кли nt 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);
}
}
Отсюда я немного застрял на том, как именно go об определении Fun c <> service => service.ServiceMethodWithResultAsync(requestDTO)
, включая ожидаемые / предполагаемые параметры requestDTO
, будут в Ldarg_1
, Ldarg_2
et c. ?
Любая и вся помощь очень ценится.