/// <summary> /// Добавляет к типу прокси реализацию метода. /// </summary> /// <param name="method">Исходный метод.</param> /// <returns>Динамический метод прокси.</returns> private MethodBuilder ImplementMethod(MethodInfo method) { var parameters = method.GetParameters(); var paramTypes = ParameterConverter.GetTypes(parameters); var proxiedMethod = DynamicTypeBuilder.DefineMethod(method.Name, MethodAttributes.Public | MethodAttributes.Virtual, method.ReturnType, paramTypes); MakeGeneric(method, proxiedMethod); var ilGenerator = proxiedMethod.GetILGenerator(); var parametersEmitter = new ParametersEmitter(ilGenerator, paramTypes); var packedArgsEmitter = new PackedArgumentsEmitter(ilGenerator); ilGenerator.Emit(OpCodes.Nop); packedArgsEmitter.EmitProxy(); // Обобщенные параметры будут известны только во время вызова // поэтому заранее собрать делегат не выйдетю var methodLambda = method.ContainsGenericParameters ? new ExtendedMethodInfo(method, null) : new ExtendedMethodInfo(method, Expressions.CreateMethodCall(method)); var token = _methodLinkStore.CreateToken(methodLambda); packedArgsEmitter.EmitMethodToken(token); var argumentsEmitter = packedArgsEmitter.EmitArguments(parameters, parametersEmitter); if (method.ContainsGenericParameters) { packedArgsEmitter.EmitGenericArguments(method.GetGenericArguments()); } ilGenerator.Emit(OpCodes.Ldarg_0); ilGenerator.Emit(OpCodes.Ldfld, _invokeDelegateField); packedArgsEmitter.EmitLoad(); ilGenerator.Emit(OpCodes.Call, MethodReferences.ActionOfObjectArrayInvoke); // Странный блок, не уверен что он нужен. for (var i = 0; i < parameters.Length; i++) { // ReSharper disable once InvertIf if (parameters[i].ParameterType.IsByRef) { parametersEmitter.EmitBeginSet(i); argumentsEmitter.EmitGet(i); parametersEmitter.EmitEndSet(i, typeof(object)); } } packedArgsEmitter.EmitReturnValue(method.ReturnType); DynamicTypeBuilder.DefineMethodOverride(proxiedMethod, method); return(proxiedMethod); }
public ArrayEmitter <object> EmitArguments(IReadOnlyList <ParameterInfo> parameters, ParametersEmitter parametersEmitter) { // object[] args = new object[paramCount]; _ilGenerator.Emit(OpCodes.Nop); _internalEmitter.EmitBeginSet((int)PackedArgumentPosition.MethodArguments); var argsEmitter = new ArrayEmitter <object>(_ilGenerator, parameters.Count); for (var i = 0; i < parameters.Count; i++) { if (parameters[i].IsOut) { continue; } // args[i] = argi; argsEmitter.EmitBeginSet(i); parametersEmitter.EmitGet(i); argsEmitter.EmitEndSet(parameters[i].ParameterType); } argsEmitter.EmitLoad(); _internalEmitter.EmitEndSet(typeof(object[])); return(argsEmitter); }