public FieldSelectorTree GenerateFromLambdaExpression <TProperty>([NotNull] Expression <Func <TRoot, TProperty> > selector)
        {
            if (selector == null)
            {
                throw new ArgumentNullException(nameof(selector));
            }

            this.rootPart = new FieldSelectorTree();
            this.Visit(selector);

            FieldSelectorPart addCurrentToMe = null;

            foreach (var childPart in this.fieldSelectorParts)
            {
                if (!this.rootPart.ChildParts.Any())
                {
                    addCurrentToMe = childPart;
                    this.rootPart.AddPart(childPart);
                }
                else if (addCurrentToMe != null)
                {
                    addCurrentToMe.AddPart(childPart);
                    addCurrentToMe = childPart;
                }
            }

            var result = this.rootPart;

            this.rootPart = null;
            return(result);
        }
        public FieldSelectorTree GenerateFullFieldSelectorTree(Int32 maximumDeep)
        {
            var result = new FieldSelectorTree();

            var childParts = this.GenerateChildTreeFromProperties(typeof(TRoot).GetProperties(), 0, maximumDeep);

            foreach (var childPart in childParts)
            {
                result.AddPart(childPart);
            }

            return(result);
        }
        /// <summary>
        /// Optimizes the whole tree.
        /// </summary>
        /// <param name="unoptimizedPart">The unoptimized tree on which the optimization is applied.</param>
        /// <param name="optimizeWith">The full tree which is used to process the optimization.</param>
        /// <exception cref="ArgumentNullException">The value of '<paramref name="optimizeWith"/>' and '<paramref name="unoptimizedPart"/>' cannot be null. </exception>
        private void Optimize([NotNull] FieldSelectorTree unoptimizedPart, [NotNull] FieldSelectorTree optimizeWith)
        {
            if (unoptimizedPart == null)
            {
                throw new ArgumentNullException(nameof(unoptimizedPart));
            }

            if (optimizeWith == null)
            {
                throw new ArgumentNullException(nameof(optimizeWith));
            }

            foreach (var combinedPart in unoptimizedPart.ChildParts.Select(m => new OptimizableFieldSelectorPart(m, optimizeWith.ChildParts.Single(n => n.PartName == m.PartName))))
            {
                this.OptimizePart(combinedPart);
            }
        }
        private FieldSelectorTree MergeRootParts([NotNull] IEnumerable <FieldSelectorTree> rootParts)
        {
            if (rootParts == null)
            {
                throw new ArgumentNullException(nameof(rootParts));
            }

            var result = new FieldSelectorTree();

            foreach (var firstLevel in rootParts.SelectMany(m => m.ChildParts).GroupBy(m => m.PartName))
            {
                var childgroup = new FieldSelectorPart(firstLevel.Key);
                foreach (var part in this.MergeChildPart(firstLevel.SelectMany(m => m.ChildParts).GroupBy(m => m.PartName)))
                {
                    childgroup.AddPart(part);
                }

                result.AddPart(childgroup);
            }

            return(result);
        }