/// <summary>
        /// Accessing a member of a class. The translation is a little tricky. For example:
        ///   arr.jets - don't translate that!
        ///   arr.jets[0].member - do translate that
        ///   [Where jets is a grouped variable]
        ///   
        ///   arr.mc.all_data[0] - translate this when "mc" is a rename, and all_data is a leaf.
        ///   
        ///   arr.jets[0].muonindex.pt - translate that to the muon array
        ///   arr.jets[0].muonsindex[0].pt - translate to the first index of the muon array.
        /// </summary>
        /// <param name="expression"></param>
        /// <returns></returns>
        protected override Expression VisitMember(MemberExpression expression)
        {
            ///
            /// If this is a bare array that is connected to the main object, then we want
            /// to not translate this. It will be delt with further above us.
            /// 

            if (expression.IsRootObjectArrayReference())
                return expression;

            ///
            /// If this is an object member on a sub-query expression, then it is too early for
            /// us to look at it. It will come back through here when it gets translated by
            /// lower level loop unroller code.
            /// 

            if (expression.Expression is Remotion.Linq.Clauses.Expressions.SubQueryExpression)
                return expression;

            ///
            /// See if the source has a "translated-to" class on it?
            /// 

            var attr = expression.Expression.Type.TypeHasAttribute<TranslateToClassAttribute>();
            if (attr != null)
            {
                return RecodeClass(expression, attr);
            }

            ///
            /// Ok, next see if this is an array recoding
            /// 

            var attrV = expression.Member.TypeHasAttribute<TTreeVariableGroupingAttribute>();
            if (attrV != null)
            {
                ///
                /// Sometimes we are deep in the middle of a lambda translation, or similar. In that case,
                /// we may not be able to walk all the way back. There is a pattern we can detect, however.
                /// 

                if (expression.Expression is ParameterExpression)
                    return expression;

                //
                // If we are looking at a [subqueryexpression].[grouping-obj].[member], which below should be translating
                // soem how, we need to wait until the subqueryexpression has been totally translated. Which will happen
                // later on, and then come back through here.
                //

                if (expression.Expression is MemberExpression)
                {
                    var mbaccess = expression.Expression as MemberExpression;
                    if (mbaccess is MemberExpression)
                    {
                        if (mbaccess.Expression is SubQueryExpression)
                            return expression;
                    }
                }

                ///
                /// Regular array recoding - so this is at the top level and is the most
                /// common kind
                /// 

                var recodedExpression = RecodeArrayGrouping(expression);
                if (recodedExpression != null)
                    return recodedExpression;

                ///
                /// The only other possibility is if this is in another object that
                /// we can decode as an array reference. In short - this guy is a 
                /// pointer from another guy to this guy.
                /// 

                var recoded = RecodeArrayPointer(expression);
                if (recoded != null)
                    return recoded;

                ///
                /// If this has an recode attribute, but we can't do it. Fail!
                /// 

                throw new NotImplementedException("Member '" + expression.Member.Name + "' is marked for array recoding, but we can't figure out what to do.");
            }

            ///
            /// Hopefully the default behavior is the right thing to do here!
            /// 

            return base.VisitMember(expression);
        }