/// <summary>
        /// Get LINQ string from filter expression (IQuaryable)
        /// </summary>
        /// <param name="filterElement">Filter expression</param>
        /// <param name="classType">Object Type for filtering (it contain filtering fields)</param>
        /// <param name="knownTypes">Known Types if use polymorphism</param>
        /// <param name="preambule">Preambule for LINQ string</param>
        /// <returns>Filter expression for LINQ</returns>
        public static string GetLinqFilteringConditions(ExpressionTreeElement filterElement, Type classType, Dictionary <Type, Type[]> knownTypes = null, string preambule = null)
        {
            var fieldLeaf = filterElement as ExpressionTreeFieldLeaf;

            if (fieldLeaf != null)
            {
                bool isFindProperty;
                var  filterProp = ReflectionHelper.GetPropertyPathFromClass(fieldLeaf.PropertyDescription.FieldName,
                                                                            classType,
                                                                            knownTypes,
                                                                            preambule,
                                                                            out isFindProperty);
                if (isFindProperty)
                {
                    if (fieldLeaf.Property.PropertyType == typeof(string))
                    {
                        return(filterProp);
                    }
                    if (fieldLeaf.Property.PropertyType == typeof(DateTime))
                    {
                        filterProp += ".Ticks";
                    }
                    else if (fieldLeaf.Property.PropertyType.IsClass &&
                             fieldLeaf.Property.PropertyType != typeof(Enum))
                    {
                        filterProp += ".HashCode";
                    }
                    else if (fieldLeaf.PropertyDescription.NumberStyle == NumberStyles.HexNumber)
                    {
                        filterProp = "(Int64(" + filterProp + ")).ToString(\"X\")";
                    }
                    return(filterProp);
                }
            }

            var valueLeaf = filterElement as ExpressionTreeValueLeaf;

            if (valueLeaf != null)
            {
                var fieldByValueLeaf = valueLeaf.Parent.Left as ExpressionTreeFieldLeaf;
                if (fieldByValueLeaf != null)
                {
                    var fieldType = ReflectionHelper.GetRealType(fieldByValueLeaf.Property.PropertyType);

                    if (fieldType == typeof(string) ||
                        fieldType == typeof(Enum) ||
                        fieldType.BaseType == typeof(Enum))
                    {
                        return("\"" + valueLeaf.FieldValue + "\"");
                    }
                    if (fieldType == typeof(DateTime))
                    {
                        return(((DateTime)valueLeaf.FieldValue).Ticks.ToString());
                    }
                    if (fieldType.IsClass)
                    {
                        return(valueLeaf.FieldValue.GetType()
                               .GetProperty("HashCode")
                               .GetValue(valueLeaf.FieldValue)
                               .ToString());
                    }
                    if (fieldByValueLeaf.PropertyDescription.NumberStyle == NumberStyles.HexNumber)
                    {
                        long value;
                        if (long.TryParse(valueLeaf.ToString(), out value))
                        {
                            return(value.ToString("X"));
                        }
                    }
                }
                return(valueLeaf.FieldValue.ToString());
            }

            var comparisonNode = filterElement as ComparisonOperatorNode;

            if (comparisonNode != null)
            {
                var comparisonNodeValueLeaf = comparisonNode.Right as ExpressionTreeValueLeaf;
                if (comparisonNodeValueLeaf != null)
                {
                    var    comparisonNodeFieldLeaf = comparisonNode.Left as ExpressionTreeFieldLeaf;
                    string expressionFieldProp;
                    bool   isFindProperty = false;
                    if (comparisonNodeFieldLeaf != null &&
                        ReflectionHelper.IsNullable(comparisonNodeFieldLeaf.Property.PropertyType))
                    {
                        expressionFieldProp = ReflectionHelper.GetPropertyPathFromClass(comparisonNodeFieldLeaf.PropertyDescription.FieldName,
                                                                                        classType,
                                                                                        knownTypes,
                                                                                        preambule,
                                                                                        out isFindProperty);
                    }
                    else
                    {
                        expressionFieldProp = GetLinqFilteringConditions(comparisonNodeFieldLeaf, classType, knownTypes, preambule);
                    }

                    if (comparisonNodeValueLeaf.FieldValue == null ||
                        (comparisonNodeValueLeaf.FieldValue is String &&
                         String.IsNullOrWhiteSpace(comparisonNodeValueLeaf.FieldValue as String)))
                    {
                        return(expressionFieldProp +
                               ComparisonFilterOperatorToLinq(comparisonNode.Operator, false, true)
                               + "null");
                    }

                    var valueStr = GetLinqFilteringConditions(comparisonNode.Right, classType, knownTypes, preambule);
                    if (comparisonNode.Operator == ComparisonOperators.StartsWith)
                    {
                        valueStr = "(\"" + valueStr + "\")";
                    }

                    var preExpression = String.Empty;

                    if (comparisonNodeFieldLeaf != null &&
                        ReflectionHelper.IsNullable(comparisonNodeFieldLeaf.Property.PropertyType) &&
                        isFindProperty)
                    {
                        preExpression = expressionFieldProp +
                                        ComparisonFilterOperatorToLinq(ComparisonOperators.NotEqual, false, true)
                                        + "null" +
                                        BooleanFilterOperatorToLinq(BooleanOperators.And);
                    }

                    return(preExpression +
                           GetLinqFilteringConditions(comparisonNodeFieldLeaf, classType, knownTypes, preambule) +
                           ComparisonFilterOperatorToLinq(comparisonNode.Operator, comparisonNodeValueLeaf.FieldValue is Enum) +
                           valueStr);
                }
            }

            var booleanNode = filterElement as BooleanOperatorNode;

            if (booleanNode != null)
            {
                return(GetLinqFilteringConditions(booleanNode.Left, classType, knownTypes, preambule) +
                       BooleanFilterOperatorToLinq(booleanNode.Operator) +
                       GetLinqFilteringConditions(booleanNode.Right, classType, knownTypes, preambule));
            }

            return(String.Empty);
        }
        /// <summary>
        /// Получить строковое выражение фильтрации
        /// </summary>
        /// <param name="filterElement">Параметры фильтра</param>
        /// <param name="filterablePropertyDescription">Описание свойств фильтрации</param>
        /// <returns>Строковое выражение фильтрации</returns>
        private string GetStringFilteringConditions(ExpressionTreeElement filterElement, FilterablePropertyDescriptionCollection filterablePropertyDescription)
        {
            var fieldLeaf = filterElement as ExpressionTreeFieldLeaf;

            if (fieldLeaf != null)
            {
                var foundFieldDescr =
                    filterablePropertyDescription.FirstOrDefault(
                        prop => prop.BoundProperty.Equals(fieldLeaf.PropertyDescription));
                if (foundFieldDescr != null)
                {
                    return(foundFieldDescr.Title);
                }
            }

            var valueLeaf = filterElement as ExpressionTreeValueLeaf;

            if (valueLeaf != null)
            {
                var fieldForValue = filterElement.Parent.Left as ExpressionTreeFieldLeaf;
                if (fieldForValue != null)
                {
                    var foundFieldDescr =
                        filterablePropertyDescription.FirstOrDefault(
                            prop => prop.BoundProperty.Equals(fieldForValue.PropertyDescription));
                    if (foundFieldDescr != null &&
                        foundFieldDescr.ValueToStringConverter != null)
                    {
                        return(foundFieldDescr.ValueToStringConverter.Convert(valueLeaf.FieldValue,
                                                                              valueLeaf.FieldValue.GetType(), null, CultureInfo.CurrentCulture).ToString());
                    }
                }
                if (valueLeaf.FieldValue is string)
                {
                    return("\"" + valueLeaf.FieldValue + "\"");
                }
                if (valueLeaf.FieldValue is DateTime)
                {
                    return("\"" + ((DateTime)valueLeaf.FieldValue).ToString(CultureInfo.CurrentCulture) + "\"");
                }
                if (valueLeaf.FieldValue == null)
                {
                    return(LocalizationDictionary.Empty);
                }
                else
                {
                    return(valueLeaf.FieldValue.ToString());
                }
            }

            var comparisonNode = filterElement as ComparisonOperatorNode;

            if (comparisonNode != null)
            {
                if (comparisonNode.Right is ExpressionTreeValueLeaf)
                {
                    if (((ExpressionTreeValueLeaf)comparisonNode.Right).FieldValue == null ||
                        (((ExpressionTreeValueLeaf)comparisonNode.Right).FieldValue is String &&
                         String.IsNullOrEmpty(((ExpressionTreeValueLeaf)comparisonNode.Right).FieldValue as String)))
                    {
                        return(GetStringFilteringConditions(comparisonNode.Left, filterablePropertyDescription)
                               + " " + ComparisonOperatorNode.OperatorToString(comparisonNode.Operator) + " "
                               + LocalizationDictionary.Empty);
                    }
                    return(GetStringFilteringConditions(comparisonNode.Left, filterablePropertyDescription)
                           + " " + ComparisonOperatorNode.OperatorToString(comparisonNode.Operator) + " "
                           + GetStringFilteringConditions(comparisonNode.Right, filterablePropertyDescription));
                }
            }

            var booleanNode = filterElement as BooleanOperatorNode;

            if (booleanNode != null)
            {
                var boolOperatorItemsSource = new LocalizableEnumItemsSource {
                    Type = typeof(BooleanOperators)
                };
                if (booleanNode.Operator == BooleanOperators.Not)
                {
                    return(boolOperatorItemsSource.Convert(booleanNode.Operator, null, null, null) + " "
                           + (booleanNode.Left is BooleanOperatorNode ? "( " : String.Empty)
                           + GetStringFilteringConditions(booleanNode.Left, filterablePropertyDescription)
                           + (booleanNode.Left is BooleanOperatorNode ? " )" : String.Empty));
                }
                return(GetStringFilteringConditions(booleanNode.Left, filterablePropertyDescription)
                       + " " + boolOperatorItemsSource.Convert(booleanNode.Operator, null, null, null) + " "
                       + GetStringFilteringConditions(booleanNode.Right, filterablePropertyDescription));
            }

            return(String.Empty);
        }