Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Drzewa wyrażeń reprezentują kod w strukturze danych przypominającej drzewo, gdzie każdy węzeł jest wyrażeniem, na przykład wywołaniem metody lub operacją binarną, taką jak x < y.
Jeśli używasz LINQ, masz doświadczenie dzięki bogatej bibliotece, w której typy Func są częścią zestawu interfejsów API. (Jeśli nie znasz LINQ, prawdopodobnie chcesz przeczytać samouczek LINQ i artykuł na temat wyrażeń lambda przed tym. Drzewa wyrażeń zapewniają bogatszą interakcję z argumentami, które są funkcjami.
Argumenty funkcji są zwykle pisane przy użyciu wyrażeń lambda podczas tworzenia zapytań LINQ. W typowym zapytaniu LINQ te argumenty funkcji są przekształcane w delegata tworzonego przez kompilator.
Już piszesz kod, który używa drzew wyrażeń. Interfejsy API LINQ platformy Entity Framework akceptują drzewa wyrażeń jako argumenty wzorca wyrażenia zapytania LINQ. Dzięki temu program Entity Framework może przetłumaczyć zapytanie napisane w języku C# na język SQL wykonywany w akiecie bazy danych. Innym przykładem jest Moq, który jest popularną platformą pozorowania dla platformy .NET.
Jeśli chcesz mieć bogatszą interakcję, musisz użyć drzew wyrażeń. Drzewa wyrażeń reprezentują kod jako strukturę, którą badasz, modyfikujesz lub wykonujesz. Te narzędzia pozwalają na manipulowanie kodem w czasie działania. Piszesz kod, który analizuje uruchomione algorytmy lub wprowadza nowe możliwości. W bardziej zaawansowanych scenariuszach można modyfikować uruchomione algorytmy, a nawet tłumaczyć wyrażenia języka C# na inny formularz do wykonywania w innym środowisku.
Kompilujesz i uruchamiasz kod reprezentowany przez drzewa wyrażeń. Tworzenie i uruchamianie drzew wyrażeń umożliwia dynamiczną modyfikację kodu wykonywalnego, wykonywanie zapytań LINQ w różnych bazach danych oraz tworzenie zapytań dynamicznych. Aby uzyskać więcej informacji na temat drzew wyrażeń w LINQ, zobacz How to use expression trees to build dynamic queries (Jak używać drzew wyrażeń do tworzenia zapytań dynamicznych).
Drzewa wyrażeń są również używane w środowisku uruchomieniowym języka dynamicznego (DLR) w celu zapewnienia współdziałania języków dynamicznych i platformy .NET oraz umożliwienia autorom kompilatora emitowania drzew wyrażeń zamiast języka Microsoft Intermediate Language (CIL). Aby uzyskać więcej informacji na temat biblioteki DLR, zobacz Dynamic Language Runtime Overview (Omówienie środowiska uruchomieniowego języka dynamicznego).
Kompilator języka C# lub Visual Basic może utworzyć drzewo wyrażeń na podstawie anonimowego wyrażenia lambda lub ręcznie utworzyć drzewa wyrażeń przy użyciu System.Linq.Expressions przestrzeni nazw.
Gdy wyrażenie lambda jest przypisywane do zmiennej typu Expression<TDelegate>, kompilator emituje kod w celu utworzenia drzewa wyrażeń reprezentującego wyrażenie lambda.
W poniższych przykładach kodu pokazano, jak kompilator języka C# utworzy drzewo wyrażeń reprezentujące wyrażenie num => num < 5lambda .
Expression<Func<int, bool>> lambda = num => num < 5;
Drzewa wyrażeń są tworzone w kodzie. Drzewo jest tworzone przez utworzenie każdego węzła i dołączenie węzłów do struktury drzewa. Dowiesz się, jak tworzyć wyrażenia w artykule dotyczącym tworzenia drzew wyrażeń.
Drzewa wyrażeń są niezmienne. Jeśli chcesz zmodyfikować drzewo wyrażeń, musisz utworzyć nowe drzewo wyrażeń, kopiując istniejący i zastępując w nim węzły. Aby przejść przez istniejące drzewo wyrażeń, należy użyć wizytatora drzewa wyrażeń. Aby uzyskać więcej informacji, zobacz artykuł dotyczący tłumaczenia drzew wyrażeń.
Po utworzeniu drzewa wyrażeń należy wykonać kod reprezentowany przez drzewo wyrażeń.
Ograniczenia
Kompilator języka C# generuje drzewa wyrażeń tylko na podstawie wyrażeń lambd (lub lambd jednowierszowych). Nie może przeanalizować wyrażeń lambda (lub wielowierszowych lambd). Aby uzyskać więcej informacji na temat wyrażeń lambda w języku C#, zobacz Wyrażenia lambda.
Istnieją nowsze elementy języka C#, które nie przekładają się dobrze na drzewa wyrażeń. Drzewa wyrażeń nie mogą zawierać await wyrażeń ani async wyrażeń lambda. Wiele funkcji dodanych w języku C# 6 i nowszych nie jest wyświetlanych dokładnie tak jak w drzewach wyrażeń. Zamiast tego nowsze funkcje są widoczne w drzewach wyrażeń w równoważnej, wcześniejszej składni, tam gdzie to możliwe. Inne konstrukcje nie są dostępne. Oznacza to, że kod, który interpretuje drzewa wyrażeń, działa tak samo, gdy wprowadzono nowe funkcje języka. Jednak nawet w przypadku tych ograniczeń drzewa wyrażeń umożliwiają tworzenie algorytmów dynamicznych, które polegają na interpretowaniu i modyfikowaniu kodu reprezentowanego jako struktura danych. Rozbudowane biblioteki, takie jak Entity Framework, mogą działać dzięki temu rozwiązaniu.
Drzewa wyrażeń nie obsługują nowych typów węzłów wyrażeń. Byłaby to zmiana łamiąca kompatybilność dla wszystkich bibliotek interpretujących drzewa wyrażeń ze względu na wprowadzenie nowych typów węzłów. Poniższa lista zawiera większość elementów języka C#, których nie można użyć:
- Metody warunkowe usunięte z danych wyjściowych
-
basedostęp - Wyrażenia grup metod, w tym adresy (
&) grupy metod i anonimowe wyrażenia metody - Odwołania do funkcji lokalnych
- Instrukcje, w tym przypisania (
=) i wyrażenia w postaci instrukcji - Metody częściowe z samą deklaracją definiującą
- Niebezpieczne operacje wskaźnika
-
dynamicOperacje -
Operatory domniemania null z literałem po lewej stronie
nulllubdefault, przypisanie domniemania null i operator propagacji null (?.) - Inicjatory tablic wielowymiarowych, właściwości indeksowanych i inicjatory słownika
- wyrażenia kolekcji
-
throwWyrażenia - Uzyskiwanie dostępu do elementów członkowskich
static virtuallubabstractinterfejsu - Wyrażenia lambda, które mają atrybuty
- Ciągi interpolowane
- Konwersje ciągów znaków UTF-8 lub literały tych ciągów.
- Wywołania metod przy użyciu argumentów zmiennych, nazwanych argumentów lub argumentów opcjonalnych
- Wyrażenia używające System.Index operatora lub System.Range, operator indeksu "from end" (
^) lub wyrażenia zakresu (..) -
asyncwyrażenia lambda lubawaitwyrażenia, w tymawait foreachiawait using -
Literały krotki, konwersje krotki, krotki
==lub!=withwyrażenia -
Odrzuca (
_), dekonstrukcja przypisania, operator dopasowywaniaiswzorca lub wyrażenie dopasowywaniaswitchwzorca - Wywołanie COM z
refpominięte przy argumentach -
ref,inluboutparametry, wartości zwracane przezref, argumentyoutlub dowolne wartości typuref struct