方法 : 式ツリーを変更する

更新 : 2007 年 11 月

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

式ツリーを変更するには

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

  2. System.Core.dll がまだ参照されていない場合は、System.Core.dll への参照を追加します。

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

    このコードについては、「方法 : 式ツリー ビジタを実装する」を参照してください。

    using ディレクティブ (Visual Basic では Imports ステートメント) をファイルに追加します。名前空間 System.Collections.Generic、System.Collections.ObjectModel、および System.Linq.Expressions に追加します。

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

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

    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);
        }
    }
    

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

  5. 式ツリーを作成し、それをメソッドに渡して変更するコードを Program.cs (Visual Basic では Module1.vb) ファイルの Main メソッドに追加します。

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

    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"))
    */
    
    

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

  6. アプリケーションをコンパイルして実行します。

参照

処理手順

方法 : 式ツリーを実行する

チュートリアル : IQueryable LINQ プロバイダの作成

方法 : 式ツリー ビジタを実装する

概念

式ツリー