in rd-net/RdFramework.Reflection/ProxyGenerator.cs [179:280]
public DynamicMethod CreateAdapter(Type selfType, MethodInfo method)
{
Assertion.Require(!method.IsGenericMethod, "generics are not supported");
Assertion.Require(!method.IsStatic, "only instance methods are supported");
lock (myModuleBuilder.Value)
{
// var type = ModuleBuilder.DefineType(selfType.FullName + "_adapter",
// TypeAttributes.Public & TypeAttributes.Sealed & TypeAttributes.Abstract & TypeAttributes.BeforeFieldInit);
var requestType = GetRequstType(method)[0];
var responseType = GetResponseType(method, unwrapTask: false);
Type returnType;
if (IsSync(method))
{
returnType = typeof(RdTask<>).MakeGenericType(responseType);
}
else
{
returnType = responseType;
}
var methodBuilder = new DynamicMethod(method.Name, returnType, new[] { selfType, typeof(Lifetime), requestType }, myModuleBuilder.Value);
var il = methodBuilder.GetILGenerator();
// Invoke adapter method
il.Emit(OpCodes.Ldarg_0); // this/self
FieldInfo[] fields;
if (requestType == typeof(Unit))
{
fields = new FieldInfo[0];
}
else
{
fields = requestType.GetFields();
}
var parameters = method.GetParameters();
for (int parameterIndex = 0, fi = 0; parameterIndex < parameters.Length; parameterIndex++)
{
if (parameters[parameterIndex].ParameterType == typeof(Lifetime))
{
LoadArgument(il, 1 /* external cancellation lifetime in SetHandler */);
}
else
{
il.Emit(OpCodes.Ldarg_2); // value tuple
int i = fi;
var f = fields;
while (i >= MaxTuplePayload)
{
il.Emit(OpCodes.Ldfld, f[MaxTuplePayload]);
f = f[MaxTuplePayload].FieldType.GetFields();
i -= MaxTuplePayload;
}
if (Mode.IsAssertion)
Assertion.Assert(parameters[parameterIndex].ParameterType == f[i].FieldType, "parameters[pi].ParameterType == fields[i].FieldType");
il.Emit(OpCodes.Ldfld, f[i]);
fi++;
}
}
// call wrapped method
il.Emit(OpCodes.Callvirt, method);
// load Unit result if necessary
if (method.ReturnType == typeof(void) && IsSync(method))
{
il.Emit(OpCodes.Ldsfld, Members.UnitInstance);
}
if (IsSync(method))
{
// Create RdTask
var taskFactoryMethod = typeof(RdTask).GetMethod(nameof(RdTask.Successful))?.MakeGenericMethod(responseType);
il.Emit(OpCodes.Call, taskFactoryMethod.NotNull("RdTask.Successful<Unit> not found"));
}
else
{
// regular task already on stack
}
il.Emit(OpCodes.Ret);
/* if (myAllowSave)
{
// shadow methods are required only for reviewing dynamic methods bodies in dotpeek
var typeBuilder = ModuleBuilder.DefineType(selfType.FullName + "_shadow");
foreach (var dynamicMethod in result)
{
var shadowMethod = typeBuilder.DefineMethod(dynamicMethod.Name, MethodAttributes.Static | MethodAttributes.Public, dynamicMethod.ReturnType, dynamicMethod.GetParameters().Select(p => p.ParameterType).ToArray());
var body = dynamicMethod.GetMethodBody();
shadowMethod.SetMethodBody(body.GetILAsByteArray(), body.MaxStackSize, new byte[0], new ExceptionHandler[0], new int[0]);
}
typeBuilder.CreateType();
}*/
return methodBuilder;
}
}