Dela via


Uttrycksträd

Uttrycksträd representerar kod i en trädliknande datastruktur, där varje nod är ett uttryck, till exempel ett metodanrop eller en binär åtgärd som x < y.

Om du använde LINQ har du erfarenhet av ett omfattande bibliotek där typerna Func ingår i API-uppsättningen. (Om du inte är bekant med LINQ vill du förmodligen läsa LINQ-självstudien och artikeln om lambda-uttryck före den här.) Uttrycksträd ger bättre interaktion med argumenten som är funktioner.

Du skriver funktionsargument, vanligtvis med Lambda-uttryck, när du skapar LINQ-frågor. I en typisk LINQ-fråga omvandlas dessa funktionsargument till ett ombud som kompilatorn skapar.

Du skriver redan kod som använder uttrycksträd. Entity Frameworks LINQ-API:er accepterar uttrycksträd som argument för LINQ-frågeuttrycksmönstret. Det gör att Entity Framework kan översätta frågan som du skrev i C# till SQL som körs i databasmotorn. Ett annat exempel är Moq, som är ett populärt mock-ramverk för .NET.

När du vill ha en mer omfattande interaktion måste du använda Uttrycksträd. Uttrycksträd representerar kod som en struktur som du undersöker, ändrar eller kör. De här verktygen ger dig möjligheten att manipulera kod under körningstid. Du skriver kod som undersöker algoritmer som körs eller matar in nya funktioner. I mer avancerade scenarier ändrar du körningsalgoritmer och översätter till och med C#-uttryck till ett annat formulär för körning i en annan miljö.

Du kompilerar och kör kod som representeras av uttrycksträd. Genom att skapa och köra uttrycksträd kan du ändra körbar kod dynamiskt, köra LINQ-frågor i olika databaser och skapa dynamiska frågor. Mer information om uttrycksträd i LINQ finns i Använda uttrycksträd för att skapa dynamiska frågor.

Uttrycksträd används också i DLR (Dynamic Language Runtime) för att tillhandahålla samverkan mellan dynamiska språk och .NET och för att göra det möjligt för kompilatorskrivare att generera uttrycksträd i stället för Microsofts mellanliggande språk (CIL). För mer information om DLR, se Översikt av dynamisk språkkörningsmiljö.

Du kan låta kompilatorn C# eller Visual Basic skapa ett uttrycksträd för dig baserat på ett anonymt lambda-uttryck, eller så kan du skapa uttrycksträd manuellt med hjälp System.Linq.Expressions av namnområdet.

När ett lambda-uttryck tilldelas en variabel av typen Expression<TDelegate>genererar kompilatorn kod för att skapa ett uttrycksträd som representerar lambda-uttrycket.

Följande kodexempel visar hur C#-kompilatorn skapar ett uttrycksträd som representerar lambda-uttrycket num => num < 5.

Expression<Func<int, bool>> lambda = num => num < 5;

Du skapar uttrycksträd i koden. Du skapar trädet genom att skapa varje nod och koppla noderna till en trädstruktur. Du lär dig hur du skapar uttryck i artikeln om att skapa uttrycksträd.

Uttrycksträd är oföränderliga. Om du vill ändra ett uttrycksträd måste du skapa ett nytt uttrycksträd genom att kopiera det befintliga och ersätta noder i det. Du använder en uttrycksträdsbesökare för att traversera det befintliga uttrycksträdet. Mer information finns i artikeln om översättning av uttrycksträd.

När du har skapat ett uttrycksträd kör du koden som representeras av uttrycksträdet.

Begränsningar

C#-kompilatorn genererar uttrycksträd endast från uttryckslambdas (eller enradslambdas). Det går inte att parsa instruktionslambdas (eller flera rader långa lambdas). Mer information om lambda-uttryck i C# finns i Lambda-uttryck.

Det finns några nyare C#-språkelement som inte översätts väl till uttrycksträd. Uttrycksträd får inte innehålla await uttryck eller async lambda-uttryck. Många av funktionerna som läggs till i C# 6 och senare visas inte exakt som de är skrivna i uttrycksträd. I stället exponeras nyare funktioner i uttrycksträd i motsvarande, tidigare syntax, där det är möjligt. Andra konstruktioner är inte tillgängliga. Det innebär att kod som tolkar uttrycksträd fungerar på samma sätt när nya språkfunktioner introduceras. Men även med dessa begränsningar gör uttrycksträd att du kan skapa dynamiska algoritmer som är beroende av att tolka och ändra kod som representeras som en datastruktur. Det gör det möjligt för omfattande bibliotek som Entity Framework att utföra det de gör.

Uttrycksträd stöder inte nya uttrycksnodtyper. Det skulle vara en störande ändring för alla bibliotek som tolkar uttrycksträd för att introducera nya nodtyper. Följande lista innehåller de flesta C#-språkelement som inte kan användas: