Ausdrucksbaumstrukturen

Aktualisiert: November 2007

Ausdrucksbaumstrukturen stellen Code auf Sprachenebene in Form von Daten dar. Die Daten werden in einer baumförmigen Struktur gespeichert. Jeder Knoten in der Ausdrucksbaumstruktur stellt einen Ausdruck dar, z. B. einen Methodenaufruf oder einen binären Vorgang wie x < y.

In der folgenden Abbildung wird ein Beispiel für einen Ausdruck und dessen Darstellung in Form einer Ausdrucksbaumstruktur gezeigt. Die verschiedenen Bestandteile des Ausdrucks sind farbcodiert, um dem entsprechenden Ausdrucksbaumstruktur-Knoten in der Ausdrucksbaumstruktur zugeordnet zu werden. Die verschiedenen Typen der Ausdrucksbaumstruktur-Knoten werden ebenfalls dargestellt.

Ausdrucksbaumstruktur-Diagramm

Das folgende Codebeispiel veranschaulicht, wie die Ausdrucksbaumstruktur, die den Lambdaausdruck num => num < 5 (C#) oder Function(num) num < 5 (Visual Basic) darstellt, in ihre Teile zerlegt werden kann.

' Import the following namespace to your project: System.Linq.Expressions

' Create an expression tree.
Dim exprTree As Expression(Of Func(Of Integer, Boolean)) = Function(ByVal num) num < 5

' Decompose the expression tree.
Dim param As ParameterExpression = exprTree.Parameters(0)
Dim operation As BinaryExpression = exprTree.Body
Dim left As ParameterExpression = operation.Left
Dim right As ConstantExpression = operation.Right

MsgBox(String.Format("Decomposed expression: {0} => {1} {2} {3}", _
                  param.Name, Left.Name, operation.NodeType, Right.Value))

' This code produces the following output:
'
' Decomposed expression: num => num LessThan 5

// Add the following using directive to your code file:
// using System.Linq.Expressions;

// Create an expression tree.
Expression<Func<int, bool>> exprTree = num => num < 5;

// Decompose the expression tree.
ParameterExpression param = (ParameterExpression)exprTree.Parameters[0];
BinaryExpression operation = (BinaryExpression)exprTree.Body;
ParameterExpression left = (ParameterExpression)operation.Left;
ConstantExpression right = (ConstantExpression)operation.Right;

Console.WriteLine("Decomposed expression: {0} => {1} {2} {3}",
                  param.Name, left.Name, operation.NodeType, right.Value);

/*  This code produces the following output:

    Decomposed expression: num => num LessThan 5
*/

Erstellen von Ausdrucksbaumstrukturen

Der System.Linq.Expressions-Namespace stellt eine API zum manuellen Erstellen von Ausdrucksbaumstrukturen bereit. Die ParameterExpression-Klasse enthält statische Factorymethoden, die Ausdrucksbaumstruktur-Knoten bestimmter Typen erstellen, z. B. einen MethodCallExpression, der einen benannten Parameterausdruck darstellt, oder einen Expression, der einen Methodenaufruf darstellt. ParameterExpression, MethodCallExpression und die anderen ausdrucksspezifischen Ausdrucksbaumstruktur-Typen werden auch im System.Linq.Expressions-Namespace definiert. Diese Typen werden vom abstrakten Typ Expression abgeleitet.

Der Compiler kann auch eine Ausdrucksbaumstruktur für Sie erstellen. Eine vom Compiler generierte Ausdrucksbaumstruktur befindet sich immer in einem Knoten vom Typ Expression<TDelegate>, d. h., der Stammknoten stellt einen Lambdaausdruck dar.

Das folgende Codebeispiel veranschaulicht zwei Möglichkeiten zum Erstellen einer Ausdrucksbaumstruktur, die den Lambdaausdruck num => num < 5 (C#) oder Function(num) num < 5 (Visual Basic) darstellt.

' Import the following namespace to your project: System.Linq.Expressions

' Manually build the expression tree for the lambda expression num => num < 5.
Dim numParam As ParameterExpression = Expression.Parameter(GetType(Integer), "num")
Dim five As ConstantExpression = Expression.Constant(5, GetType(Integer))
Dim numLessThanFive As BinaryExpression = Expression.LessThan(numParam, five)
Dim lambda1 As Expression(Of Func(Of Integer, Boolean)) = _
  Expression.Lambda(Of Func(Of Integer, Boolean))( _
        numLessThanFive, _
        New ParameterExpression() {numParam})

' Let the compiler generate the expression tree for
' the lambda expression num => num < 5.
Dim lambda2 As Expression(Of Func(Of Integer, Boolean)) = Function(ByVal num) num < 5

// Add the following using directive to your code file:
// using System.Linq.Expressions;

// Manually build the expression tree for 
// the lambda expression num => num < 5.
ParameterExpression numParam = Expression.Parameter(typeof(int), "num");
ConstantExpression five = Expression.Constant(5, typeof(int));
BinaryExpression numLessThanFive = Expression.LessThan(numParam, five);
Expression<Func<int, bool>> lambda1 =
    Expression.Lambda<Func<int, bool>>(
        numLessThanFive,
        new ParameterExpression[] { numParam });

// Let the compiler generate the expression tree for
// the lambda expression num => num < 5.
Expression<Func<int, bool>> lambda2 = num => num < 5;

Unveränderlichkeit von Ausdrucksbaumstrukturen

Ausdrucksbaumstrukturen sind unveränderlich. Das bedeutet, dass Sie eine neue Ausdrucksbaumstruktur erstellen müssen, wenn Sie eine Ausdrucksbaumstruktur ändern möchten. Dazu kopieren Sie die vorhandene Struktur und nehmen die gewünschten Änderungen vor. Sie können einen Ausdrucksbaumstruktur-Besucher verwenden, um die vorhandene Ausdrucksbaumstruktur zu durchlaufen. Weitere Informationen finden Sie unter Gewusst wie: Implementieren eines Ausdrucksbaumstruktur-Besuchers und Gewusst wie: Ändern von Ausdrucksbaumstrukturen.

Lambdaausdrücke

Wenn ein Lambdaausdruck einer Variablen vom Typ Expression<TDelegate> zugewiesen wird, gibt der Compiler eine Ausdrucksbaumstruktur aus, die den Lambdaausdruck darstellt. Einige Standardabfrageoperator-Methoden, die in der Queryable-Klasse definiert sind, verfügen beispielsweise über Parameter vom Typ Expression<TDelegate>. Wenn Sie diese Methoden aufrufen, können Sie einen Lambdaausdruck übergeben, und der Compiler generiert eine Ausdrucksbaumstruktur.

Der Expression<TDelegate>-Typ stellt die Compile-Methode bereit, die den durch die Ausdrucksbaumstruktur dargestellten Code in ein ausführbares Delegat kompiliert. Dieser ausführbare Code ist dem ausführbaren Code gleichwertig, der generiert worden wäre, wenn der Lambdaausdruck ursprünglich einem Delegattyp zugewiesen worden wäre.

Hinweis:

Nur die Ausdrucksbaumstrukturen, die Funktionen darstellen, d. h. Expression<TDelegate> und der übergeordnete Typ LambdaExpression, können in ausführbaren Code kompiliert werden. Um andere Typen von Ausdrucksbaumstrukturen auszuführen, müssen Sie diese zunächst in einen LambdaExpression-Knoten einbinden. Sie können einen solchen LambdaExpression abrufen, indem Sie die Lambda-Methode aufrufen und die Ausdrucksbaumstruktur als Argument übergeben.

Siehe auch

Aufgaben

Gewusst wie: Ausführen von Ausdrucksbaumstrukturen

Gewusst wie: Ändern von Ausdrucksbaumstrukturen

Gewusst wie: Implementieren eines Ausdrucksbaumstruktur-Besuchers

Konzepte

Ausdrucksbaumstrukturen in LINQ

Lambda-Ausdrücke

Referenz

Lambda-Ausdrücke (C#-Programmierhandbuch)

System.Linq.Expressions