Exemplo n.º 1
0
        /// <summary>
        /// BinaryExpressionの子を走査します。
        /// </summary>
        /// <param name="node">走査する式</param>
        /// <returns>式またはいずれかの部分式が変更された場合は変更された式。それ以外の場合は元の式。</returns>
        protected override Expression VisitBinary(BinaryExpression node)
        {
            //--- AND/OR : 左右を保持する要素として生成
            //--- 比較演算子 (<, <=, >=, >, ==, !=) : 左辺のプロパティ名と右辺の値を抽出
            switch (node.NodeType)
            {
            case ExpressionType.AndAlso:
            case ExpressionType.OrElse:
            {
                var element = new PredicateElement(node.NodeType.ToPredicateOperator());
                return(this.VisitCore(element, () => base.VisitBinary(node)));
            }

            case ExpressionType.LessThan:
            case ExpressionType.LessThanOrEqual:
            case ExpressionType.GreaterThan:
            case ExpressionType.GreaterThanOrEqual:
            case ExpressionType.Equal:
            case ExpressionType.NotEqual:
            {
                var element = this.ParseBinary(node);
                return(this.VisitCore(element, () => base.VisitBinary(node)));
            }
            }
            return(base.VisitBinary(node));
        }
Exemplo n.º 2
0
 /// <summary>
 /// UnaryExpressionの子を走査します。
 /// </summary>
 /// <param name="node">走査する式。</param>
 /// <returns>式またはいずれかの部分式が変更された場合は変更された式。それ以外の場合は元の式。</returns>
 protected override Expression VisitUnary(UnaryExpression node)
 {
     //--- !x.CanPlay の形式は xCanPlay != true として扱う
     if (node.NodeType == ExpressionType.Not)
     {
         if (this.IsBooleanProperty(node.Operand as MemberExpression))
         {
             var element = new PredicateElement(PredicateOperator.NotEqual);
             return(this.VisitCore(element, () => base.VisitUnary(node)));
         }
     }
     return(base.VisitUnary(node));
 }
Exemplo n.º 3
0
        /// <summary>
        /// 指定された条件式要素自身とその子孫要素を取得します。
        /// </summary>
        /// <param name="element">条件式要素</param>
        /// <returns>条件式要素のコレクション</returns>
        public static IEnumerable <PredicateElement> DescendantsAndSelf(this PredicateElement element)
        {
            if (element == null)
            {
                throw new ArgumentNullException(nameof(element));
            }

            yield return(element);

            foreach (var x in element.Descendants())
            {
                yield return(x);
            }
        }
Exemplo n.º 4
0
        /// <summary>
        /// 指定された条件式要素の子要素を取得します。
        /// </summary>
        /// <param name="element">条件式要素</param>
        /// <returns>条件式要素のコレクション</returns>
        public static IEnumerable <PredicateElement> Children(this PredicateElement element)
        {
            if (element == null)
            {
                throw new ArgumentNullException(nameof(element));
            }

            if (element.HasChildren)
            {
                yield return(element.Left);

                yield return(element.Right);
            }
        }
Exemplo n.º 5
0
        /// <summary>
        /// 指定された条件式要素の子孫要素を取得します。
        /// </summary>
        /// <param name="element">条件式要素</param>
        /// <returns>条件式要素のコレクション</returns>
        public static IEnumerable <PredicateElement> Descendants(this PredicateElement element)
        {
            if (element == null)
            {
                throw new ArgumentNullException(nameof(element));
            }

            foreach (var child in element.Children())
            {
                yield return(child);

                foreach (var grandChild in child.Descendants())
                {
                    yield return(grandChild);
                }
            }
        }
Exemplo n.º 6
0
        /// <summary>
        /// MethodCallExpressionの子を走査します。
        /// </summary>
        /// <param name="node">走査する式</param>
        /// <returns>式またはいずれかの部分式が変更された場合は変更された式。それ以外の場合は元の式。</returns>
        protected override Expression VisitMethodCall(MethodCallExpression node)
        {
            //--- Enumerable.Contains
            if (node.Method.DeclaringType == typeof(Enumerable))
            {
                if (node.Method.Name == nameof(Enumerable.Contains))
                {
                    //--- プロパティ名を取得
                    var propertyName = this.ExtractMemberName(node.Arguments[1]);
                    if (propertyName == null)
                    {
                        throw new InvalidOperationException();
                    }

                    //--- 要素生成
                    //--- in句は1000件以上あるとエラーが発生するためorでつなぐ
                    var source = (this.ExtractValue(node.Arguments[0]) as IEnumerable)
                                 .Cast <object>()
                                 .Buffer(1000)
                                 .Select(x => x.ToArray());

                    PredicateElement root = null;
                    foreach (var x in source)
                    {
                        if (root != null)
                        {
                            var parent = new PredicateElement(PredicateOperator.OrElse);
                            parent.Left  = new PredicateElement(PredicateOperator.Contains, this.Parameter.Type, propertyName, x);
                            parent.Right = root;
                            root         = parent;
                            continue;
                        }
                        root = new PredicateElement(PredicateOperator.Contains, this.Parameter.Type, propertyName, x);
                    }
                    return(this.VisitCore(root, () => base.VisitMethodCall(node)));
                }
            }

            //--- default
            return(base.VisitMethodCall(node));
        }
Exemplo n.º 7
0
        /// <summary>
        /// MemberExpressionの子を走査します。
        /// </summary>
        /// <param name="node">走査する式</param>
        /// <returns>式またはいずれかの部分式が変更された場合は変更された式。それ以外の場合は元の式。</returns>
        protected override Expression VisitMember(MemberExpression node)
        {
            //--- 「x => x.CanPlay == true」ではなく「x => x.CanPlay」のような書き方への対応
            if (this.IsBooleanProperty(node as MemberExpression))
            {
                //--- 親要素がない
                var info   = (PropertyInfo)node.Member;
                var parent = this.Cache.Count == 0 ? null : this.Cache.Peek();
                if (parent == null)
                {
                    var element = new PredicateElement(PredicateOperator.Equal, info.PropertyType, info.Name, true);
                    return(this.VisitCore(element, () => base.VisitMember(node)));
                }

                switch (parent.Operator)
                {
                //--- && か || の場合は左辺/右辺のどちらか
                case PredicateOperator.AndAlso:
                case PredicateOperator.OrElse:
                {
                    var element = new PredicateElement(PredicateOperator.Equal, info.PropertyType, info.Name, true);
                    return(this.VisitCore(element, () => base.VisitMember(node)));
                }

                //--- == / != / !x.CanPlay の場合
                case PredicateOperator.Equal:
                case PredicateOperator.NotEqual:
                    if (parent.PropertyName == null)
                    {
                        parent.Type         = info.PropertyType;
                        parent.PropertyName = info.Name;
                        parent.Value        = true;
                    }
                    break;
                }
            }
            return(base.VisitMember(node));
        }
Exemplo n.º 8
0
        /// <summary>
        /// 式を走査します。
        /// </summary>
        /// <param name="element">要素生成</param>
        /// <param name="baseCall">基底メソッド呼び出しデリゲート</param>
        /// <returns>式またはいずれかの部分式が変更された場合は変更された式。それ以外の場合は元の式。</returns>
        private Expression VisitCore(PredicateElement element, Func <Expression> baseCall)
        {
            //--- 親要素と関連付け
            var parent = this.Cache.Count == 0 ? null : this.Cache.Peek();

            if (parent != null)
            {
                if (parent.Left == null)
                {
                    parent.Left = element;
                }
                else if (parent.Right == null)
                {
                    parent.Right = element;
                }
                else
                {
                    throw new InvalidOperationException();
                }
            }

            //--- 子要素を解析
            this.Cache.Push(element);
            var result = baseCall();

            this.Cache.Pop();

            //--- キャッシュがなくなった場合 (= Root)
            if (this.Cache.Count == 0)
            {
                this.Root = element;
            }

            //--- ok
            return(result);
        }