public DynamicMethod CreateAdapter()

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