protected override IElement VisitIfThen(IfThenElement ifThen)
        {
            ifThen = (IfThenElement)base.VisitIfThen(ifThen);

            var cachingField = (FieldInfo)null;
            return Matcher
                .For(ifThen.Condition)
                    .OneOf(ExpressionType.Equal)
                    .AsBinary()
                    .LeftAndRight(
                        leftOrRight => leftOrRight.AsPropertyOrField().Field()
                                                  .Match(IsLambdaCachingField)
                                                  .AssignTo(out cachingField),

                        leftOrRight => leftOrRight.AsConstant().ValueIsNull()
                    )

                .For(ifThen.Then)
                    .Count(1)
                    .For(list => list.Single()).As<MemberAssignmentElement>()
                        .Match(a => a.Member == cachingField)
                        .Do(a => collectedFieldValues.Add((FieldInfo)a.Member, a.Value))

                .For(ifThen.Else).Count(0)

                .IfMatched(() => null, ifThen);
        }
        private bool TryExtractElseIfThenEndsWithReturn(IfThenElement ifThen, IList<IElement> elements, int index)
        {
            if (ifThen.Else.Count == 0 || !(ifThen.Then.Last() is ReturnElement))
                return false;

            elements.InsertRange(index + 1, ifThen.Else);
            ifThen.Else.Clear();
            return true;
        }
        protected override IElement VisitIfThen(IfThenElement ifThen)
        {
            ifThen = (IfThenElement)base.VisitIfThen(ifThen);
            if (ifThen.Then.Count != 1 || ifThen.Else.Count != 1)
                return ifThen;

            var thenAssignment = ifThen.Then[0] as VariableAssignmentElement;
            var elseAssignment = ifThen.Else[0] as VariableAssignmentElement;

            if (thenAssignment == null || elseAssignment == null || thenAssignment.VariableIndex != elseAssignment.VariableIndex)
                return ifThen;

            return new VariableAssignmentElement(thenAssignment.VariableIndex, Expression.Condition(
                ifThen.Condition, thenAssignment.Value, elseAssignment.Value
            ));
        }
        protected override IElement VisitIfThen(IfThenElement ifThen)
        {
            ifThen = (IfThenElement)base.VisitIfThen(ifThen);
            if (ifThen.Else.Count > 0)
                return ifThen;

            if (ifThen.Then.Count > 1)
                return ifThen;

            var thenAsIf = ifThen.Then[0] as IfThenElement;
            if (thenAsIf == null)
                return ifThen;

            return new IfThenElement(
                Expression.AndAlso(ifThen.Condition, thenAsIf.Condition),
                thenAsIf.Then, thenAsIf.Else
            );
        }
        private static void TryInlineIfThenReturnFollowedByReturn(IfThenElement ifThen, IList<IElement> elements, int index)
        {
            if (index == elements.Count - 1)
                return;

            if (ifThen.Then.Count != 1 || ifThen.Else.Count > 0)
                return;

            var returnInIf = ifThen.Then.Single() as ReturnElement;
            var returnAfterIf = elements[index + 1] as ReturnElement;
            if (returnInIf == null || returnAfterIf == null)
                return;

            if (returnInIf.Result == null || returnAfterIf.Result == null)
                return;

            elements[index] = new ReturnElement(Expression.Condition(
                ifThen.Condition,
                returnInIf.Result,
                returnAfterIf.Result
            ));

            elements.RemoveAt(index + 1);
        }