方法: 式ツリーを変更する (C# および Visual Basic)

ここでは、式ツリーを変更する方法について説明します。式ツリーは変更不可であるため、直接変更を加えることができません。式ツリーを変更するには、既存の式ツリーのコピーを作成する必要があります。コピーを作成する際に、必要な変更を加えます。ExpressionVisitor クラスを使用して既存の式ツリーを走査し、走査した各ノードをコピーすることができます。

[!メモ]

ExpressionVisitor クラスのソース コードは、CodePlex の Web サイトで参照できます。

式ツリーを変更するには

  1. Visual Studio で、新しいコンソール アプリケーション プロジェクトを作成します。

  2. AndAlsoModifier クラスをプロジェクトに追加します。

    このクラスは ExpressionVisitor クラスを継承します。AND 条件演算を表す式を変更するための特別なクラスです。これを使用して、条件 AND から条件 OR に処理を変更します。それを行うには、AND 条件式は二項式で表されるため、このクラスによって基本型の VisitBinary メソッドをオーバーライドします。渡される式が AND 条件演算を表す場合、VisitBinary メソッドでは、AND 条件演算子ではなく OR 条件演算子を含む新しい式がコードによって作成されます。VisitBinary に渡される式が AND 条件演算を表さない場合、メソッドでは基本クラスの実装が延期されます。基本クラスのメソッドにより、渡された式ツリーに似たノードが作成されますが、そのノードのサブツリーは、ビジタにより再帰的に作成される式ツリーに置き換えられます。

    ファイルに using ディレクティブ (Visual Basic の場合は Imports ステートメント) を System.Linq.Expressions 名前空間で追加します。

    Public Class AndAlsoModifier
        Inherits ExpressionVisitor
    
        Public Function Modify(ByVal expr As Expression) As Expression
            Return Visit(expr)
        End Function
    
        Protected Overrides Function VisitBinary(ByVal b As BinaryExpression) As Expression
            If b.NodeType = ExpressionType.AndAlso Then
                Dim left = Me.Visit(b.Left)
                Dim right = Me.Visit(b.Right)
    
                ' Make this binary expression an OrElse operation instead 
                ' of an AndAlso operation.
                Return Expression.MakeBinary(ExpressionType.OrElse, left, right, _
                                             b.IsLiftedToNull, b.Method)
            End If
    
            Return MyBase.VisitBinary(b)
        End Function
    End Class
    
    public class AndAlsoModifier : ExpressionVisitor
    {
        public Expression Modify(Expression expression)
        {
            return Visit(expression);
        }
    
        protected override Expression VisitBinary(BinaryExpression b)
        {
            if (b.NodeType == ExpressionType.AndAlso)
            {
                Expression left = this.Visit(b.Left);
                Expression right = this.Visit(b.Right);
    
                // Make this binary expression an OrElse operation instead of an AndAlso operation.
                return Expression.MakeBinary(ExpressionType.OrElse, left, right, b.IsLiftedToNull, b.Method);
            }
    
            return base.VisitBinary(b);
        }
    }
    
  3. 式ツリーを作成し、それをメソッドに渡して変更するコードを Program.cs (Visual Basic では Module1.vb) ファイルの Main メソッドに追加します。

    次のコードでは、AND 条件演算を含む式を作成します。次に、AndAlsoModifier クラスのインスタンスを作成して、このクラスの Modify メソッドにその式を渡します。元の式ツリーと変更された式ツリーの両方が出力され、変更内容が表示されます。

    ファイルに using ディレクティブ (Visual Basic の場合は Imports ステートメント) を System.Linq.Expressions 名前空間で追加します。

            Dim expr As Expression(Of Func(Of String, Boolean)) = _
                Function(name) name.Length > 10 AndAlso name.StartsWith("G")
    
            Console.WriteLine(expr)
    
            Dim modifier As New AndAlsoModifier()
            Dim modifiedExpr = modifier.Modify(CType(expr, Expression))
    
            Console.WriteLine(modifiedExpr)
    
            ' This code produces the following output:
            ' name => ((name.Length > 10) && name.StartsWith("G"))
            ' name => ((name.Length > 10) || name.StartsWith("G"))
    
    
                Expression<Func<string, bool>> expr = name => name.Length > 10 && name.StartsWith("G");
                Console.WriteLine(expr);
    
                AndAlsoModifier treeModifier = new AndAlsoModifier();
                Expression modifiedExpr = treeModifier.Modify((Expression) expr);
    
                Console.WriteLine(modifiedExpr);
    
                /*  This code produces the following output:
    
                    name => ((name.Length > 10) && name.StartsWith("G"))
                    name => ((name.Length > 10) || name.StartsWith("G"))
                */
    
    
  4. アプリケーションをコンパイルして実行します。

参照

処理手順

方法: 式ツリーを実行する (C# および Visual Basic)

概念

式ツリー (C# および Visual Basic)