/// <summary>
        /// Generates a list of <see cref="FieldSelectorPart"/> for each <see cref="PropertyInfo"/> in the supplied list.
        /// </summary>
        /// <param name="propertyInfos">The <see cref="PropertyInfo"/> instances.</param>
        /// <param name="currentDeep">The current deep of the recursion.</param>
        /// <param name="maximumDeep">The maximum recursion deep to prevent a <see cref="StackOverflowException" /> on endless nested types.</param>
        /// <returns>The list of <see cref="FieldSelectorPart"/>.</returns>
        /// <exception cref="ArgumentNullException">The value of '<paramref name="propertyInfos"/>' cannot be null. </exception>
        private IEnumerable <FieldSelectorPart> GenerateChildTreeFromProperties([NotNull] IEnumerable <PropertyInfo> propertyInfos, Int32 currentDeep, Int32 maximumDeep)
        {
            if (propertyInfos == null)
            {
                throw new ArgumentNullException(nameof(propertyInfos));
            }

            if (currentDeep == maximumDeep)
            {
                yield break;
            }

            foreach (var propertyInfo in propertyInfos)
            {
                var partName  = this.partNameExtractor.ExtractPartName(propertyInfo);
                var childPart = new FieldSelectorPart(partName);

                var nextType = propertyInfo.PropertyType;

                if (!nextType.IsPrimitive())
                {
                    if (propertyInfo.PropertyType.IsIEnumerable() && !propertyInfo.PropertyType.IsPrimitive())
                    {
                        nextType = propertyInfo.PropertyType.GetSingleGenericParameter();
                    }

                    foreach (var childPartOfChildPart in this.GenerateChildTreeFromProperties(nextType.GetProperties(), currentDeep + 1, maximumDeep))
                    {
                        childPart.AddPart(childPartOfChildPart);
                    }
                }

                yield return(childPart);
            }
        }
        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);
        }
        private IEnumerable <FieldSelectorPart> MergeChildPart([NotNull] IEnumerable <IGrouping <String, FieldSelectorPart> > groupedPart)
        {
            if (groupedPart == null)
            {
                throw new ArgumentNullException(nameof(groupedPart));
            }

            foreach (var group in groupedPart)
            {
                var mergedChildPart = new FieldSelectorPart(group.Key);
                foreach (var childPart in this.MergeChildPart(group.SelectMany(m => m.ChildParts).GroupBy(m => m.PartName)))
                {
                    mergedChildPart.AddPart(childPart);
                }

                yield return(mergedChildPart);
            }
        }
        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);
        }