Czytałem o funkcji drzewa wyrażeń i o tym, jak tworzyć delegatów za pomocą wyrażeń lambda. Wciąż nie mogę się dowiedzieć, w jakim scenariuszu jest on przydatny iw jakim realnym przykładzie powinienem go użyć.kiedy iw jakim scenariuszu używać drzewa wyrażeń
Odpowiedz
Podstawowym zastosowaniem drzewek wyrażeń jest poza procesami dostawców LINQ, takich jak LINQ do SQL.
Kiedy piszesz coś takiego:
var query = people.Where(x => x.Age > 18)
.Select(x => x.Name);
te wyrażenia lambda może albo być konwertowane do delegatów, które następnie mogą być wykonane (są one w LINQ do obiektu) lub mogą być konwertowane do drzewek wyrażeń, które mogą być analizowane przez źródło zapytań i odpowiednio do nich stosowane (np. przez przekształcenie ich w SQL, wywołania usługi sieciowej itp.). Różnica polega na tym, że drzewa wyrażenia reprezentują kod jako danych. W razie potrzeby można je skompilować w delegatów, ale zwykle (w każdym razie w LINQ) nie są wykonywane bezpośrednio - po prostu są sprawdzane, aby znaleźć logikę, którą zawierają.
Drzewa wyrażeń są również szeroko używane w środowisku wykonawczym języka dynamicznego, gdzie reprezentują kod, który powinien zostać wykonany podczas oceny wyrażenia dynamicznego. Drzewa ekspresji są do tego odpowiednie, ponieważ można je ponownie skomponować i zepsuć, a po ich skompilowaniu uzyskany IL jest kompilowany JIT jak zwykle.
Większość deweloperów nigdy nie będzie musiała mieszać z API drzewa wyrażeń, chociaż ma kilka innych zastosowań.
Oprócz LINQ, kolejnym bardzo prostym przypadkiem jest wyodrębnienie zarówno nazwy, jak i wartości właściwości. Używam tego w płynnym API do sprawdzania poprawności obiektów transferu danych. Bezpieczniej jest przekazać jeden parametr lambda, aby zdefiniować zarówno nazwę, jak i wartość, zamiast mieć drugi parametr dla nazwy i ryzykować, że programiści popełnią błąd.
Oto przykład (minus wszystkie kontrole bezpieczeństwa i inny personel sprzątający):
public Validator<T> Check<T>(Expression<Func<T>> expr) {
// Analyse the expression as data
string name = ((MemberExpression) expr.Body).Member.Name;
// Compile and execute it to get the value
T value = (expr.Compile())();
return new Validator<T>(name, value);
}
Przykład zastosowania:
Check(() => x.Name).NotNull.MinLength(1);
Check(() => x.Age).GreaterThan(18);
Bardzo ładne API sprawdzania poprawności, chociaż wydajność prawdopodobnie nie jest tak dobra z powodu kompilacji wyrażeń –
Tak, wystąpi narzut wydajności. W sumie pomyślałem, że zysk z niezawodności był tego wart. Kompilacja jest wykonywana tylko raz dla każdej właściwości, a następnie można młotkować skonstruowany obiekt walidatora tak bardzo, jak chcesz. –
użyłem wyrażenia drzew, aby null-safe oceniającego:
string name = myObject.NullSafeEval(x => x.Foo.GetBar(42).Baz.Name, "Default");
Ta metoda analizuje i przepisuje drzewo wyrażeń, aby wstawiać sprawdzenia zerowe przed każdym pro perty lub wywołanie metody wzdłuż "ścieżki" do Name
. Jeśli napotkana zostanie wartość pusta po drodze, zwracana jest wartość domyślna.
Zobacz realizacja here
ekspresyjne drzewa są również powszechnie stosowane w celu uniknięcia odnoszące się do nieruchomości przez twarde kodowania jej nazwę w ciąg:
private string _foo;
public string Foo
{
get { return _foo; }
set
{
_foo = value;
OnPropertyChanged(() => Foo);
// Rather than:
// OnPropertyChanged("Foo");
}
}
static string GetPropertyName<T>(Expression<Func<T>> expr)
{
var memberExpr = expr.Body as MemberExpression;
if (memberExpr == null)
throw new ArgumentException("expr", "The expression body must be a member expression");
return memberExpr.Member.Name;
}
protected void OnPropertyChanged<T>(Expression<Func<T>> expr)
{
OnPropertyChanged(GetPropertyName(expr));
}
To pozwala skompilować czasu sprawdzania i nazwisko refaktoringu
Cool. Gdyby tylko jakiś rodzaj odpowiednika syntaktycznego został wbudowany w język ...
@ Christiana Haytera: Czy mógłbyś pokazać przykład? – Douglas
@Douglas: Przykład czego? –
- 1. jak korzystać z GC.KeepAlive() iw jakim celu
- 2. Wydajność skompilowanego drzewa wyrażeń
- 3. Jawne drzewa wyrażeń
- 4. Łączenie wielu wyrażeń drzewa
- 5. W jakim scenariuszu haker otrzyma tabelę, ale nie kod PHP?
- 6. Jak określić głębokość drzewa wyrażeń C#?
- 7. Kiedy należy używać ramek HTML?
- 8. Notacja Postfix do drzewa wyrażeń
- 9. Tworzenie drzewa wyrażeń w R
- 10. Kiedy należy używać wyrażeń lambda dostarczanych z C# 3.0?
- 11. Kiedy używać `method_missing`
- 12. C# Metoda dynamiczna - IL vs drzewa wyrażeń
- 13. Drzewa wyrażeń Linq w zwartej strukturze
- 14. Dodawanie węzła/właściwości do drzewa wyrażeń
- 15. Wyodrębnij nazwę metody z drzewa wyrażeń?
- 16. Uzyskiwanie dostępu do indeksu z drzewa wyrażeń
- 17. Drzewa wyrażeń - niepotrzebne przekształcenie w int32
- 18. Kiedy używać node.js i kiedy używać ajax?
- 19. kiedy używać zadania i kiedy używać wątku?
- 20. Kiedy używać viewDidLoad i kiedy używać awakeFromNib
- 21. W jakim języku należy używać wtyczki Pidgin?
- 22. Kiedy należy używać wzorców as w celu identyfikacji typowych wyrażeń podrzędnych?
- 23. Kiedy należy używać git skrytki?
- 24. Kiedy najbardziej przydatne są konstruktory wyrażeń ASP.NET?
- 25. Kiedy używać Formatera wartości i kiedy używać Resolvera wartości
- 26. PHP: Kiedy używać funkcji i kiedy używać metod statycznych?
- 27. Kiedy używać undef_method i kiedy używać metody remove_method?
- 28. Kiedy używać komponentów Seaside i kiedy używać prostych obiektów renderowania?
- 29. Kiedy używać tablicy bajtów i kiedy używać strumienia?
- 30. Kiedy używać LEFT JOIN i kiedy używać INNER JOIN?
Dzięki Jon. Chciałbym uzyskać przykład z życia, w którym mogę go użyć. Dostałem tę koncepcję nieco, ale jeśli nie mogę wymyślić scenariusza, w którym używanie drzewa Expression jest lepsze niż konwencjonalny sposób działania, nie będę czuł się komfortowo w moim umyśle. – DotNetInfo
@Nimesh: It * can * może czasami być przydatny w tworzeniu programów odpornych na refaktory, które muszą korzystać z refleksji. Określając właściwość poprzez wyrażenie lambda skonwertowane na delegata zamiast nazwy (jako łańcuch), można dodać ciąg znaków w czasie wykonywania i mieć pewność, że jest poprawny. Ale jest to naprawdę poważny przypadek - dotyczy głównie LINQ i DLR (edycja odzwierciedla to drugie). –