コード例 #1
0
        public void Modify(AssemblyDefinition assembly)
        {
            var mainModule = assembly.MainModule;

            var getInterceptorMethod = mainModule.Import(typeof(InterceptorRegistry).GetMethod(nameof(InterceptorRegistry.GetInterceptor)));
            var interceptMethod      = mainModule.Import(typeof(IInterceptor).GetMethod(nameof(IInterceptor.Intercept)));
            var objectReference      = mainModule.Import(typeof(object));
            var getMethodFromHandle  =
                mainModule.Import(typeof(MethodBase).GetMethod(nameof(MethodBase.GetMethodFromHandle),
                                                               new Type[] { typeof(RuntimeMethodHandle), typeof(RuntimeTypeHandle) }));

            var targetType = mainModule.Types.FirstOrDefault(t => t.Name == "SampleClassWithInstanceMethod");

            if (targetType == null)
            {
                return;
            }

            var targetMethod = targetType.Methods.First(m => m.Name == "DoSomething");
            var methodBody   = targetMethod.Body;

            var IL = methodBody.GetILProcessor();

            var instructions = methodBody.Instructions.ToArray();

            methodBody.Instructions.Clear();

            var argsArray = targetMethod.AddLocal <object[]>();

            foreach (var instruction in instructions)
            {
                if (instruction.OpCode != OpCodes.Call)
                {
                    IL.Append(instruction);
                    continue;
                }

                var methodCall      = ((MethodReference)instruction.Operand);
                var parameterCount  = methodCall.Parameters.Count;
                var localParameters = new VariableDefinition[parameterCount];

                var thisParameter = targetMethod.AddLocal <object>();

                for (int i = 0; i < parameterCount; i++)
                {
                    localParameters[i] = targetMethod.AddLocal <object>();
                    if (methodCall.Parameters[i].ParameterType.IsValueType)
                    {
                        IL.Emit(OpCodes.Box, methodCall.Parameters[i].ParameterType);
                    }

                    IL.Emit(OpCodes.Stloc, localParameters[i]);
                }

                if (!methodCall.Resolve().IsStatic)
                {
                    IL.Emit(OpCodes.Stloc, thisParameter);
                }
                else
                {
                    IL.Emit(OpCodes.Ldnull);
                    IL.Emit(OpCodes.Stloc, thisParameter);
                }

                IL.Emit(OpCodes.Call, getInterceptorMethod);
                IL.Emit(OpCodes.Ldc_I4, parameterCount);
                IL.Emit(OpCodes.Newarr, objectReference);
                IL.Emit(OpCodes.Stloc, argsArray);

                int j = 0;
                foreach (var variableDefinition in localParameters.Reverse())
                {
                    IL.Emit(OpCodes.Ldloc, argsArray);

                    IL.Emit(OpCodes.Ldc_I4, j++);
                    IL.Emit(OpCodes.Ldloc, variableDefinition);

                    IL.Emit(OpCodes.Stelem_Ref);
                }

                IL.Emit(OpCodes.Ldloc, thisParameter);
                IL.Emit(OpCodes.Ldloc, argsArray);
                IL.Emit(OpCodes.Ldtoken, methodCall);
                IL.Emit(OpCodes.Ldtoken, methodCall.DeclaringType);
                IL.Emit(OpCodes.Call, getMethodFromHandle);

                IL.Emit(OpCodes.Callvirt, interceptMethod);

                if (methodCall.ReturnType.MetadataType == MetadataType.Void)
                {
                    IL.Emit(OpCodes.Pop);
                }
                else
                {
                    IL.Emit(OpCodes.Unbox_Any, methodCall.ReturnType);
                }
            }
        }