Uwaga
Dostęp do tej strony wymaga autoryzacji. Może 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 < 5
lambda .
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 będą obsługiwać 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
-
base
dostę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
-
dynamic
Operacje -
Operatory domniemania null z literałem po lewej stronie
null
lubdefault
, przypisanie domniemania null i operator propagacji null (?.
) - Inicjatory tablic wielowymiarowych, właściwości indeksowanych i inicjatory słownika
- wyrażenia kolekcji
-
throw
Wyrażenia - Uzyskiwanie dostępu do elementów członkowskich
static virtual
lubabstract
interfejsu - 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 (..
) -
async
wyrażenia lambda lubawait
wyrażenia, w tymawait foreach
iawait using
-
Literały krotki, konwersje krotki, krotki
==
lub!=
with
wyrażenia -
Odrzuca (
_
), dekonstrukcja przypisania, operator dopasowywaniais
wzorca lub wyrażenie dopasowywaniaswitch
wzorca - Wywołanie COM z
ref
pominięte przy argumentach -
ref
,in
lubout
parametry, wartości zwracane przezref
, argumentyout
lub dowolne wartości typuref struct