Ejemplo n.º 1
0
        public static void Rewrite(PointCut asyncVoidPc, MethodDefinition asyncVoidMethod, VariableDefinition taskVar)
        {
            asyncVoidMethod.Body.SimplifyMacros();

            var asyncVoidMBType = asyncVoidMethod.Module.Import(typeof(AsyncVoidMethodBuilder));
            var asyncTaskMBType = asyncVoidMethod.Module.Import(typeof(AsyncTaskMethodBuilder));

            asyncVoidMethod.Body.Variables.First(v => v.VariableType.IsTypeOf(asyncVoidMBType)).VariableType = asyncTaskMBType;

            Instruction    loadStateMachineInst = null;
            FieldReference builderField         = null;

            foreach (var inst in asyncVoidMethod.Body.Instructions)
            {
                var method = inst.Operand as MethodReference;

                if (method != null && method.DeclaringType.IsTypeOf(asyncVoidMBType))
                {
                    var newMethod = asyncVoidMethod.Module.Import(asyncTaskMBType.Resolve().Methods.First(m => m.Name == method.Name));

                    if (method.IsGenericInstance)
                    {
                        newMethod = newMethod.MakeGeneric(newMethod.DeclaringType, ((IGenericInstance)method).GenericArguments.ToArray());
                    }

                    inst.Operand = newMethod;

                    if (method.Name == "Create")
                    {
                        loadStateMachineInst = inst.Previous;
                        builderField         = (FieldReference)inst.Next.Operand;
                    }
                }
            }

            var stateMachine = builderField.DeclaringType.Resolve();

            stateMachine.Fields.First(v => v.FieldType.IsTypeOf(asyncVoidMBType)).FieldType = asyncTaskMBType;

            foreach (var md in stateMachine.Methods)
            {
                RewriteMethod(md);
            }

            var getTask = asyncTaskMBType.Resolve().Properties.First(p => p.Name == "Task").GetMethod;

            if (loadStateMachineInst == null || builderField == null)
            {
                throw new NotSupportedException("Unsupported state machine implementation");
            }

            asyncVoidPc.SetVariable(taskVar,
                                    c =>
            {
                c.InsertBefore(c.CreateInstruction(loadStateMachineInst.OpCode, (VariableDefinition)loadStateMachineInst.Operand));
                c.InsertBefore(c.CreateInstruction(OpCodes.Ldflda, builderField));
                c.InjectMethodCall(getTask);
            });

            asyncVoidMethod.Body.OptimizeMacros();
        }