Καλώς ορίσατε στο dotNETZone.gr - Σύνδεση | Εγγραφή | Βοήθεια
σε

 

Αρχική σελίδα Ιστολόγια Συζητήσεις Εκθέσεις Φωτογραφιών Αρχειοθήκες

Expression Trees

Îåêßíçóå áðü ôï ìÝëïò dimos.homatas. Τελευταία δημοσίευση από το μέλος Παναγιώτης Καναβός στις 09-09-2011, 15:55. Υπάρχουν 10 απαντήσεις.
Ταξινόμηση Δημοσιεύσεων: Προηγούμενο Επόμενο
  •  07-09-2011, 12:13 67111

    Expression Trees

    Καλησπέρα σας,

    η ερώτηση είναι απλή: που χρησιμεύουν τα expression trees; που μπορώ να τα χρησιμοποιήσω πρακτικά;

    Το μόνο που πάει το μυαλό μου είναι το serialization - η δυνατότητα να μπορούμε να αποθηκεύουμε κώδικα και να εκτελούμε κώδικα πχ από μία ΒΔ. Δυστυχώς όμως, και εδώ ο τομέας χωλαίναι: τα expression trees δεν είναι serializable (και μάλλον σωστά). Βρήκα ένα 3rd party serializer, αλλά έχει τα όριά του ( Expression Tree Serialization ), στην δοκιμή που έκανα μπόρεσα να κάνω serialize μόνο ένα lambda και όχι ένα υπάρχον procedure.

    Επίσης να επισημάνω και αυτό το σημείο, απευθείας από το MSDN :

    "In .NET Framework 4, the expression trees API also supports assignments and control flow expressions such as loops, conditional blocks, and try-catch blocks. By using the API, you can create expression trees that are more complex than those that can be created from lambda expressions by the C# and Visual Basic compilers."

    Και λέω λοιπόν, για να επανέλθω: άντε και χρησιμοποιώ το .ΝΕΤ 4 (τώρα έχω 3.5). Και πάλι, που μπορώ να χρησιμοποιήσω πρακτικά τα expression trees? Σε κάποιο design pattern ίσως;



    "When the darkness rises up from inside - that is normal.
    It's when you reach down to pull it up - that the noxious warnings sound."
    Tuzak, Farscape
  •  07-09-2011, 16:59 67114 σε απάντηση της 67111

    Απ: Expression Trees

    Προσωπικά τα expression trees έρχονται στο μυαλό μου κάθε φορά που σκέφτομαι το Linq2<Something> - στο <Something> βάλε ότι θες. Ουσιαστικά είναι αυτά που πέρνουν τα lamdas και τα μετατρέπουν σε SQL όταν μιλάμε για Linq2Sql, σε FBQL όταν μιλάμε για Linq2Facebook, κ.ο.κ.

    Αυτό είναι μια μορφή serialization - δεν είναι όμως προσέγγιση για αυτό που περιγράφεις: να αποθηκεύεις κώδικα σε Db και μετά να τον κάνεις retrieve και να τον εκτελείς...

     

    George J.


    George J. Capnias: Χειροπρακτικός Υπολογιστών, Ύψιστος Γκουράρχης της Κουμπουτερολογίας
    w: capnias.org, t: @gcapnias, l: gr.linkedin.com/in/gcapnias
    dotNETZone.gr News
  •  08-09-2011, 09:20 67119 σε απάντηση της 67114

    Απ: Expression Trees

    Ευχαριστώ για την απάντηση, έχει πάρει το μάτι μου κάτι 'Linq to Amazon' κλπ.

    Οπότε καταλήγουμε στο συμπέρασμα ότι πέρα από την δημιουργία Linq providers, δεν έχουμε άλλη χρήση για τα expression trees;

    "When the darkness rises up from inside - that is normal.
    It's when you reach down to pull it up - that the noxious warnings sound."
    Tuzak, Farscape
  •  08-09-2011, 12:12 67120 σε απάντηση της 67119

    Απ: Expression Trees

    Λάθος. Τα expression trees χρησιμεύουν σε πολύ περισσότερα πράγματα από LINQ providers. Όσο για το serialization ... δεν χρησιμοποιούνται τα expression trees για serialization αλλά το αντίστροφο: αν θέλεις να στείλεις ένα expression tree από ένα process σε ένα άλλο, μπορείς να χρησιμοποιήσεις ΚΑΙ .NET serialization. Ή να μετατρέψεις το expression tree σε ένα κοινό string format (π.χ. SQL, FORTRAN, καντονέζικα) και να στείλεις αυτή τη μορφή.

    Τα expression trees σχετίζονται άμεσα με το parsing. To expression tree είναι η δομή που δημιουργείται όταν γίνεται parse ένα expression είτε είναι LINQ είτε αριθμητική πράξη. Αυτή τη δομή μετά την επεξεργάζεται το σύστημα ή ο δικός σου κώδικας για να κάνει "κάτι". Αυτό μπορεί να είναι να δημιουργήσει SQL statements και Sharepoint CAML queries, ή να εκτελέσει κώδικα για κάθε διαφορετικό statement και operator που θα βρει. Επιπλέον, μπορείς να κάνεις compile ένα expression tree και να εκτελέσεις τον κώδικα που αντιπροσωπεύει.

    Για παράδειγμα, το DLR δημιουργεί expression trees για να εκτελέσει τον κώδικα που του δίνεις σε μία δυναμική γλώσσα στο runtime. Ή μπορείς εσύ να φτιάξεις ένα mini parser που θα παίρνει π.χ. φόρμουλες που δίνει ο χρήστης (σε στυλ Excel) και θα τις μετατρέπει σε expression tree για εκτέλεση.  Αν θέλεις να φτιάξεις δυναμικά ένα LINQ Query θα πρέπει να φτιάξεις το αντίστοιχο LINQ expression tree με κώδικα.

    Τα expression trees και τα lambdas συνδέονται γιατί στο .ΝΕΤ μπορείς άνετα να περάσεις ένα lambda είτε ως function, είτε ως expression χωρίς να αλλάξεις τον κώδικα σου. Αυτό επιτρέπει κάποιες πολύ ενδιαφέρουσες τεχνικές.

     Για παράδειγμα, στο Silverlight και το WPF (και όχι μόνο) σηκώνεις το PropertyChanged event για να ειδοποιήσεις ότι κάποιο property άλλαξε. Το event δέχεται ως παράμετρο ένα string και προφανώς, αν αλλάξεις όνομα στο property χωρίς να αλλάξεις και το string, την πάτησες. Ένας τρόπος να αποφύγεις το πρόβλημα είναι να ορίσεις είναι ένα function του στυλ RaisePropertyChanged(()=>MyPropertyName). Αν η RaisePropertyChanged οριστεί ως RaisePropertyChanged<T>(Funct<T> param1), το param1 είναι ένα function που θα σου γυρίσει την τιμή του property. Άν όμως οριστεί ως Expression<Func<T>>, είναι ένα expression tree το οποίο περιέχει το function. Από αυτό το expression μετά μπορώ να τραβήξω το όνομα του property. Αν τώρα κάποιος αλλάξει το όνομα του property χωρίς να αλλάξει και την κλήση του RaisePropertyChanged, ο compiler θα χτυπήσει και θα σε ειδοποιήσει.

    Την παρακάτω (απλοποιημένη) υλοποίηση την έχω αντιγράψει από το Caliburn.Micro

    public virtual void NotifyOfPropertyChange<TProperty>(Expression<Func<TProperty>> property) {
         RaisePropertyChanged(property.GetMemberInfo().Name);
    }

    και καλείται άνετα ως NotifyOfPropertyChange(()=>MyProperty);

    Σε αυτή τη συζήτηση θα βρεις και άλλη μία παρόμοια χρήση. Το client library του Sharepoint απαιτεί να του δώσεις με τον ίδιο τρόπο lambdas με τα ονόματα των πεδίων που θέλεις να φορτώσεις. Χωρίς να έχω ψάξει σε βάθος τον κώδικα του Sharepoint, υποθέτω ότι θα μπορούσαν να στείλουν το expression tree στον server για να μετατρέψουν το DataTable που σου  επιστρέφει ο server στο OData stream που περιμένει ο client.

    Τα expression trees επιτρέπουν επίσης το metaprogramming: Να δώσεις τη δυνατότητα στο πρόγραμμα σου να φτιάχνει το ίδιο τον κώδικα που πρέπει να εκτελέσει. Για παράδειγμα, αν έχεις μία περίπλοκη διαδικασία της οποίας τα βήματα εξαρτώνται από τα στοιχεία που δίνει ο χρήστης, μπορείς να τη σπάσεις σε απλά βήματα και να δομήσεις το expression tree της συνολικής διαδικασίας με βάση τα στοιχεία του χρήστη.

    Ένα παράδειγμα metaprogramming θα ήταν π.χ. σε ένα GIS σύστημα ή σε ένα παιχνίδι, να ορίσεις τις ενέργεις που θα πρέπει να γίνουν αν μετακινήσεις ένα αντικείμενο από το σημείο Α στο Β ανάλογα με τις συνθήκες: υπάρχει δρόμος, έχουμε βενζίνη ή ενέργεια, ειδοποιώ άλλα συστήματα για τη μετακίνηση? Μπορείς μάλιστα να δεις τα LINQ statements ως μία πολύ απλή μορφή metaprogramming, καθώς τα Where, Select κλπ δημιουργούν βήμα - βήμα τον κώδικα που θα εκτελεστεί στο τέλος όταν καλέσεις την ToList(). 


    Παναγιώτης Καναβός, Freelancer
    Twitter: http://www.twitter.com/pkanavos
  •  08-09-2011, 14:10 67129 σε απάντηση της 67120

    Απ: Expression Trees

    Οκ, κατανοητό. Αλλά δεν μπορώ να κάνω serialize ένα expression tree, λέει ότι δεν είναι serializable. 

    Οπότε, και μιας και με ενδιαφέρει περισσότερο το concept της αποθήκευσης δημιουργημένου κώδικα από κώδικα, επεκτείνω το ερώτημα: πως μπορώ να έχω persistent storage (οποιασδήποτε μορφής) ενός expression tree; 

    Την ερώτηση την έκανα αρχικά γιατί από όσο είδα, δεν μπορούσα να τα αποθηκεύσω - τόσο με binary serializer όσο και με την βιβλιοθήκη που προανέφερα.

    "When the darkness rises up from inside - that is normal.
    It's when you reach down to pull it up - that the noxious warnings sound."
    Tuzak, Farscape
  •  08-09-2011, 14:55 67131 σε απάντηση της 67129

    Απ: Expression Trees

    Αυτό είναι άλλη ερώτηση. Ξέρεις τί να κάνεις το expression tree, έχεις ένα έτοιμο και θέλεις για κάποιο λόγο να το αποθηκεύσεις ή να το στείλεις σε άλλο κώδικα. (Αλήθεια, γιατί?)

    Το serialization δεν απαιτεί τα αντικείμενα που αποθηκεύεις να έχουν το Serializable attribute. Αν το έχουν, μπορείς να χρησιμοποιήσεις τους built-in serializers του .NET για δημιουργήσεις την ενδιάμεση μορφή κειμένου ή binary και το αντίστροφο. Επειδή όμως αυτή η μορφή είναι αρκετά φλύαρη, ένας custom serializer θα δημιουργήσει πολύ μικρότερο string/binary και μπορεί να είναι και αρκετά γρηγορότερος. Αν μάλιστα πρέπει να χρησιμοποιήσεις κάποιο συγκεκριμμένο format, o custom serializer είναι απαραίτητος.

    Αλήθεια, τί προσπαθείς να κάνεις? Αφού ήδη έχεις βρει κάποιο Expression tree serializer. Στην αρχική σου ερώτηση λες ότι δεν μπορεί να κάνει serialize procedures. Δηλαδή? Θέλεις να κάνει serialize την κλήση σε κάποιο άγνωστο procedure ή περιμένεις να κάνει serialize τον κώδικα του stored procedure?

    Άν σκεφτείς πάντως ότι τα expression trees είναι το ενδιάμεσο αποτέλεσμα parsing κάποιας γλώσσας, προτιμότερο είναι να αποθηκεύσεις αυτή την αρχική μορφή παρά το expression tree. Σχεδόν πάντα (εκτός και αν μιλάμε για XML) η αρχική μορφή είναι πολύ μικρότερη από το expression tree. Δεν έχει μεγάλο νόημα να κάνεις serialize την ενδιάμεση μορφή όταν υπάρχει διαθέσιμη η αρχική.


    Παναγιώτης Καναβός, Freelancer
    Twitter: http://www.twitter.com/pkanavos
  •  08-09-2011, 15:24 67133 σε απάντηση της 67131

    Απ: Expression Trees

    Λοιπόν, ψάχνοντας για expression tree serialization έπεσα σε αυτή την παρόμοια ερώτηση στα MSDN Forums, όπου κάποιος χρησιμοποιεί το MetaLINQ (κάτι σαν Linq to BLOCKED EXPRESSION για να δημιουργήσει XML . To MetaLINQ όμως έχει 2 χρόνια να ανανεωθεί και δεν υποστηρίζει recursion. Έπεσα και στο Expression Tree Serializer το οποίο φαίνεται να είναι ένα rewrite σε .NET 4.0  του serializer που είχε μπει στο MSDN Code.

    Ως τώρα έχω βρει δύο περιπτώσεις όπου χρειάζεται το expression serialization:

    1. Να γράψεις ένα LINQ query στον client και να το εκτελέσεις στο server (όπως στα WCF RIA Services του Silverlight)
    2. Να δημιουργήσεις criteria που αφορούν π.χ. ένα EF query χωρίς να έχεις φορτώσει το αντίστοιχο context. Είναι το αντίστοιχο των DetachedCriteria του NHibernate, το οποίο είναι serializable.

    Εσύ τί προσπαθείς να κάνεις?


    Παναγιώτης Καναβός, Freelancer
    Twitter: http://www.twitter.com/pkanavos
  •  08-09-2011, 16:42 67135 σε απάντηση της 67133

    Απ: Expression Trees

    Δεν έχω κάποιο συγκεκριμένο λόγο ακόμα - και ο λόγος είναι η πρώτη ερώτηση! Αν ήξερα που μπορώ να τα χρησιμοποιήσω, ίσως και να τα χρησιμοποιούσα!

    Τα ανακάλυψα σχετικά πρόσφατα από τον δρόμο delegates -> anonymous methods -> lambda expressions -> action & func.

    Γενικότερα έψαχνα (μέσω LINQ) να βρω πως γίνονται κάποια πράγματα που τα έχω δει στην Lisp (εντελώς χομπιστικά), πχ να εφαρμόζω κάποιο method επιλεκτικά πάνω σε ένα collection από objects. 

    Ε, ψάχνοντας μου έκανε κλικ το concept του expression tree, και πιάστηκα από το ότι έχουμε κώδικα σε ένα object κλπ. Επίσης, ξαναθυμούμενος την Lisp, όπου ο κώδικας ο ίδιος αποτελείται από τις ίδιες δομές που αποτελούνται και τα data, είπα να κοιτάξω και το αντίστοιχο concept στο .ΝΕΤ, με αποτέλεσμα τον τοίχο αυτόν.

    Αυτό που σκέφτομαι πάντως, είναι ότι εάν θα μπορούσα να έχω serializable expression trees (από .ΝΕΤ 4 για τους λόγους που προανέφερα, loops, branching etc), μία πρακτική εφαρμογή θα ήταν να έχω τον κώδικα (ή κάποια components) αποθηκευμένο σε μία βάση με αποτέλεσμα, εάν θέλω να κάνω κάποιο update, απλά να αλλάζω τα δεδομένα στην βάση και να μην μπαίνω στην διαδικασία της αποστολής των εκτελέσιμων/update κλπ

    Τώρα που το σκέφτομαι, μήπως καλύπτομαι από τα action/func;


    "When the darkness rises up from inside - that is normal.
    It's when you reach down to pull it up - that the noxious warnings sound."
    Tuzak, Farscape
  •  08-09-2011, 23:27 67142 σε απάντηση της 67111

    Απ: Expression Trees

    Εγώ τα είχα βρει πολύ χρήσιμα όταν ήθελα να φτιάξω κώδικα δυναμικά όταν έτρεχε η εφαρμογή χωρίς να μπλέξω με IL. Δεν γνωρίζω αν υπάρχει κάποιος καλύτερος τρόπος τώρα, αλλά τουλάχιστον η σύνταξη των expression trees μου φάνηκε πιό εύκολη. Αν έχουν φτιαχτεί μόνο γιά LINQ τότε λάθος μου ...

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
     
    Option Strict On
    Imports System.Reflection.Emit
    Imports System.Linq.Expressions
    
    Public Class Form1
        Private Delegate Function SquareDelegate(Of Result, Parameter)(ByVal p As Parameter) As Result
    
        Private Sub cmdIL_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
        Handles cmdIL.Click
            Dim args As Type() = {GetType(Integer)}
            Dim Square As New DynamicMethod("Square", GetType(Long), args)
            Dim il As ILGenerator = Square.GetILGenerator
    
            il.Emit(OpCodes.Ldarg_0)    ' Βάλτο στο stack
            il.Emit(OpCodes.Conv_I8)    ' cast σε long
            il.Emit(OpCodes.Dup)        ' Push το ίδιο argument στο stack
            il.Emit(OpCodes.Mul)        ' multiply
            il.Emit(OpCodes.Ret)        ' Return με κάποια τιμή (αν υπάρχει)
    
            Dim invokeSquare As SquareDelegate(Of Long, Integer) =
                CType(Square.CreateDelegate(GetType(SquareDelegate(Of Long, Integer))), SquareDelegate(Of Long, Integer))
    
            Console.WriteLine("5 * 5 = {0}", invokeSquare(5))
        End Sub
    
        Private Sub cmdTree_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
        Handles cmdTree.Click
            Dim param As ParameterExpression = Expression.Parameter(GetType(Integer), "param")
            Dim Square As Expression = Expression.Convert(Expression.Multiply(param, param), GetType(Long))
    
            Console.WriteLine("5 * 5  = {0}", Expression.Lambda(Of Func(Of Integer, Long))(Square, param).Compile()(5))
        End Sub
    End Class
  •  09-09-2011, 15:31 67172 σε απάντηση της 67142

    Απ: Expression Trees

    Σας ευχαριστώ όλους για το input σας.
    "When the darkness rises up from inside - that is normal.
    It's when you reach down to pull it up - that the noxious warnings sound."
    Tuzak, Farscape
  •  09-09-2011, 15:55 67174 σε απάντηση της 67172

    Απ: Expression Trees

    Να προσθέσω ότι τα Expression Trees σε μεγάλο βαθμό ΕΙΝΑΙ για το LINQ αλλά δεν είναι δεμένα με αυτό (πέρα από το namespace). Είναι τόσο γενικά που μπορούν να χρησιμοποιηθούν σε άπειρες άλλες περιπτώσεις (μου ήρθε το πρωί: triggers και actions σε state machines).

    Από την άλλη, δεν φτιάχτηκαν για δυναμικό προγραμματισμό. Για το σκοπό αυτό υπάρχει το DLR το οποίο σου δίνει τις δυναμικές δυνατότητες που σου παρέσει η LISP και η Ruby. Υπάρχει επίσης και η F# η οποία είναι μία πλήρως functional γλώσσα αν θέλεις τις functional λειτουργίες της LISP.

     

     


    Παναγιώτης Καναβός, Freelancer
    Twitter: http://www.twitter.com/pkanavos
Προβολή Τροφοδοσίας RSS με μορφή XML
Με χρήση του Community Server (Commercial Edition), από την Telligent Systems