Пример #1
0
        protected override Expression VisitTry(TryExpression node)
        {
            // Visit finally/fault block first
            BlockInfo block = new BlockInfo {
                InFinally = true
            };

            _blocks.Push(block);
            Expression @finally = Visit(node.Finally);
            Expression fault    = Visit(node.Fault);

            block.InFinally = false;

            LabelTarget finallyEnd = block.FlowLabel;

            if (finallyEnd != null)
            {
                if (@finally != null)
                {
                    @finally = Expression.Label(finallyEnd, @finally);
                }
                if (fault != null)
                {
                    fault = Expression.Label(finallyEnd, fault);
                }
                // Make a new target, which will be emitted after the try
                block.FlowLabel = Expression.Label();
            }

            Expression         @try     = Visit(node.Body);
            IList <CatchBlock> handlers = Visit(node.Handlers, VisitCatchBlock);

            _blocks.Pop();

            if (@try == node.Body &&
                handlers == node.Handlers &&
                @finally == node.Finally &&
                fault == node.Fault)
            {
                return(node);
            }

            if (!block.HasFlow)
            {
                return(Expression.MakeTry(@try, @finally, fault, handlers));
            }

            //  If there is a control flow in finally, emit outer:
            //  try {
            //      // try block body and all catch handling
            //  } catch (Exception all) {
            //      saved = all;
            //  } finally {
            //      finally_body
            //      if (saved != null) {
            //          throw saved;
            //      }
            //  }
            //
            //  If we have a fault handler we turn this into the better:
            //  try {
            //      // try block body and all catch handling
            //  } catch (Exception all) {
            //      saved = all;
            //      fault_body
            //      throw saved
            //  }

            if (handlers.Count > 0)
            {
                @try = Expression.MakeTry(@try, null, null, handlers);
            }

            var all = Expression.Variable(typeof(Exception), "$exception");

            if (@finally != null)
            {
                handlers = new[] { Expression.Catch(all.Type, Expression.Empty()) };
                @finally = Expression.Block(
                    @finally,
                    Expression.Condition(
                        Expression.NotEqual(all, Expression.Constant(null, all.Type)),
                        Expression.Throw(all),
                        Expression.Empty()
                        )
                    );
            }
            else
            {
                handlers = new[] {
                    Expression.Catch(
                        all.Type,
                        Expression.Block(fault, Expression.Throw(all))
                        )
                };
                fault = null;
            }

            // Emit flow control
            return(Expression.Block(
                       new ParameterExpression[] { all },
                       Expression.MakeTry(@try, @finally, fault, handlers),
                       Expression.Label(block.FlowLabel),
                       MakeFlowControlSwitch(block)
                       ));
        }