示例#1
0
        bool HandleAnonymousMethod(ObjectCreateExpression objectCreateExpression, Expression target, IMethod methodRef)
        {
            if (!context.Settings.AnonymousMethods)
            {
                return(false);                // anonymous method decompilation is disabled
            }
            if (target != null && !(target is IdentifierExpression || target is ThisReferenceExpression || target is NullReferenceExpression))
            {
                return(false);                // don't copy arbitrary expressions, deal with identifiers only
            }
            // Anonymous methods are defined in the same assembly
            MethodDef method = methodRef.ResolveMethodWithinSameModule();

            if (!IsAnonymousMethod(context, method))
            {
                return(false);
            }

            var ilRanges = objectCreateExpression.GetAllRecursiveILRanges();

            // Create AnonymousMethodExpression and prepare parameters
            AnonymousMethodExpression ame = new AnonymousMethodExpression();

            ame.CopyAnnotationsFrom(objectCreateExpression); // copy ILRanges etc.
            ame.RemoveAnnotations <IMethod>();               // remove reference to delegate ctor
            ame.AddAnnotation(method);                       // add reference to anonymous method
            ame.Parameters.AddRange(AstBuilder.MakeParameters(method, isLambda: true));
            ame.HasParameterList = true;

            // rename variables so that they don't conflict with the parameters:
            foreach (ParameterDeclaration pd in ame.Parameters)
            {
                EnsureVariableNameIsAvailable(objectCreateExpression, pd.Name);
            }

            // Decompile the anonymous method:

            DecompilerContext subContext = context.Clone();

            subContext.CurrentMethod        = method;
            subContext.CurrentMethodIsAsync = false;
            subContext.ReservedVariableNames.AddRange(currentlyUsedVariableNames);
            MemberMapping  mm;
            BlockStatement body = AstMethodBodyBuilder.CreateMethodBody(method, subContext, ame.Parameters, out mm);

            body.AddAnnotation(mm);
            TransformationPipeline.RunTransformationsUntil(body, v => v is DelegateConstruction, subContext);
            body.AcceptVisitor(this, null);


            bool isLambda = false;

            if (ame.Parameters.All(p => p.ParameterModifier == ParameterModifier.None))
            {
                isLambda = body.Statements.Count == 1 && body.Statements.Single() is ReturnStatement &&
                           body.HiddenStart == null && body.HiddenEnd == null;
            }
            // Remove the parameter list from an AnonymousMethodExpression if the original method had no names,
            // and the parameters are not used in the method body
            if (!isLambda && method.Parameters.SkipNonNormal().All(p => string.IsNullOrEmpty(p.Name)))
            {
                var parameterReferencingIdentifiers =
                    from ident in body.Descendants.OfType <IdentifierExpression>()
                    let v = ident.Annotation <ILVariable>()
                            where v != null && v.IsParameter && method.Parameters.Contains(v.OriginalParameter)
                            select ident;
                if (!parameterReferencingIdentifiers.Any())
                {
                    ame.AddAnnotation(ame.Parameters.GetAllRecursiveILRanges());
                    ame.Parameters.Clear();
                    ame.HasParameterList = false;
                }
            }

            // Replace all occurrences of 'this' in the method body with the delegate's target:
            foreach (AstNode node in body.Descendants)
            {
                if (node is ThisReferenceExpression)
                {
                    var newTarget = target.Clone();
                    newTarget.RemoveAllILRangesRecursive();
                    newTarget.AddAnnotation(node.GetAllRecursiveILRanges());
                    node.ReplaceWith(newTarget);
                }
            }
            Expression replacement;

            if (isLambda)
            {
                LambdaExpression lambda = new LambdaExpression();
                lambda.CopyAnnotationsFrom(ame);
                ame.Parameters.MoveTo(lambda.Parameters);
                var        stmtIlRanges = body.Statements.Single().GetAllILRanges();
                Expression returnExpr   = ((ReturnStatement)body.Statements.Single()).Expression;
                if (stmtIlRanges.Count > 0)
                {
                    returnExpr.AddAnnotation(stmtIlRanges);
                }
                returnExpr.Remove();
                lambda.Body = returnExpr;
                replacement = lambda;
            }
            else
            {
                ame.Body    = body;
                replacement = ame;
            }
            var expectedType = objectCreateExpression.Annotation <TypeInformation>().ExpectedType.Resolve();

            if (expectedType != null && !expectedType.IsDelegate())
            {
                var simplifiedDelegateCreation = (ObjectCreateExpression)objectCreateExpression.Clone();
                simplifiedDelegateCreation.Arguments.Clear();
                simplifiedDelegateCreation.Arguments.Add(replacement);
                replacement = simplifiedDelegateCreation;
            }
            objectCreateExpression.ReplaceWith(replacement);
            replacement.AddAnnotation(ilRanges);
            return(true);
        }