|
Îåêßíçóå áðü ôï ìÝëïò Mitsaras. Τελευταία δημοσίευση από το μέλος Mitsaras στις 09-03-2006, 22:18. Υπάρχουν 6 απαντήσεις.
-
09-03-2006, 03:17
|
-
Mitsaras
-
-

-
Μέλος από τις 12-09-2005
-
Θεσσαλονίκη
-
Δημοσιεύσεις 818
-
-
|
Επιστροφή nullable αντικειμένου και τα assumptions του .net!
Μια... ενδιαφέρουσα ιστορία που μου συνέβη πριν από λίγο (κάθομαι και γράφω κώδικα τέτοια ώρα, είναι πολλά τα λεφτά...):
Λοιπόν, το σενάριο έχει ως εξής: Έχω μια λίστα αντικειμένων, σε μια global κλάση, η οποία προσπελάζεται από ένα property. Το property αυτό ελέγει αν η λίστα είναι null, και φορτώνει τις τιμές από τη βάση πριν τις επιστρέψει. Ένα χειροκίνητο σύστημα caching δηλαδή (ναι, ξέρω, πάσχω από το σύνδρομο Not Invented Here). Στην εκκίνηση του web application, η λίστα είναι null, και δημιουργείται/γεμίζει με το πρώτο request.
Φανταστείτε την έκπληξή μου τώρα, όταν διαπίστωνα πως από το πρώτο request κιόλας, η λίστα ήταν ήδη δημιουργημένη (με μηδενικό περιεχόμενο βεβαίως), χωρίς να έχει προηγηθεί κανενός είδους initialization (το property είναι set, και το initialization γίνεται αποκλειστικά και μόνο εντός του property). Τελικά ανακάλυψα, ότι το method του business layer που επέστρεφε τη λίστα τύπου List<int, Item>, βρίσκονταν ολοκληρωτικά σε try/catch/finally (καθώς για την κλήση του Data access object χρησιμοποιούσα transaction, οπότε σε περίπτωση "στραβής", στο catch έκανα Rollback), αλλά το return αυτού του Method, βρίσκονταν (βλακωδώς, ας μην ξεχνάμε την ώρα) εκτός του try/catch/finally!
Οπότε, το αγαπητό framework μάλλον υπέθετε ότι το return αντικείμενο ήταν σωστά initialized, και οπωσδήποτε not nullable. Μετακινώντας το μέσα στο try και το catch, το πρόβλημα λύθηκε.
Χμ... μπορεί κάποιος να με διαφωτίσει παραπάνω σχετικά με τα inner workings που μπορεί να έλαβαν χώρα στην περίπτωση αυτή;
Μην αφήνετε τα media να σας "ταΐζουν"!
|
|
-
09-03-2006, 08:50
|
|
Απ: Επιστροφή nullable αντικειμένου και τα assumptions του .net!
Είναι πρωί, μόλις ήπια τον πρώτο καφέ και φεύγω να ακούσω τον Kelman για ADO.NET, οπότε κι εγώ δεν είμαι στην καλύτερη μου αλλά ...
Αν με το global εννοείς static ή shared κλάση, θα πρέπει να ξέρεις ότι τα shared πεδία δημιουργούνται όλα μαζί πριν από την πρώτη κλήση. Τα περί try...catch δεν τα κατάλαβα (δεν έπιασε ακόμα ο καφές). Αν εννοείς ότι ορίζεις τη λίστα μέσα στο try...catch αλλά την επιστρέφεις εκτός try...catch, εεε, χμ. Αυτό δεν έπρεπε να το κάνει. Θα έπρεπε να είχε βγάλει compile error. Αν μπορείς, δώσε ένα sample για να το καταλάβω.
Παναγιώτης Καναβός, Freelancer Twitter: http://www.twitter.com/pkanavos
|
|
-
09-03-2006, 14:41
|
-
Mitsaras
-
-

-
Μέλος από τις 12-09-2005
-
Θεσσαλονίκη
-
Δημοσιεύσεις 818
-
-
|
Απ: Επιστροφή nullable αντικειμένου και τα assumptions του .net!
Ναι, το πρόβλημα είναι πως το method του Data acces tier, δημιουργεί το επιστρεφόμενο αντικείμενο στην αρχή: public static Dictionary<int, Item> LoadItems() { Dictionary<int, Item> items = new Dictionary<int, Item>();
try { ... } catch (...) { } finally { ... }
return items; }
και το επιστρέφει στο τέλος ως "σίγουρα" δημιουργηθέν. Το θέμα είναι, ότι το property που εξετάζουμε, έχει ως εξής:
public Dictionary<int, Item> ItemList { get { if (this._itemList != null) return this._itemList; else { this._itemList = DataAccessTier.LoadItems(); return this._itemList; } } } private Dictionary<int, Item> _itemList;
όπου στον costructor της κλάσσης αυτής, θέτω this._itemList = null; Η κλάση αυτή βρίσκεται ως static πεδίο στο Global.asax (είναι derived από το HttpApplication προφανώς).
Παρ' όλ' αυτά, το Dictionary κατά το runtime εμφανίζονταν να έχει δημιουργηθεί, χωρίς να έχω κάνει ποτέ τέτοια κλήση.
Μην αφήνετε τα media να σας "ταΐζουν"!
|
|
-
09-03-2006, 18:24
|
|
Απ: Επιστροφή nullable αντικειμένου και τα assumptions του .net!
Απ' ότι βλέπω, στην LoadItems δημιουργείς αρχικά μια άδεια λίστα την οποία θα πρέπει να γεμίζεις μέσα στο try, σωστά? Η return συμπεριφέρεται σωστά όταν το επιστρέφει άδειο σε περίπτωση exception. Η λίστα δημιουργήθηκε πλήρως από το new.
Μήπως εννοείς κάτι άλλο?
Παναγιώτης Καναβός, Freelancer Twitter: http://www.twitter.com/pkanavos
|
|
-
09-03-2006, 19:13
|
-
Mitsaras
-
-

-
Μέλος από τις 12-09-2005
-
Θεσσαλονίκη
-
Δημοσιεύσεις 818
-
-
|
Απ: Επιστροφή nullable αντικειμένου και τα assumptions του .net!
Με αυτή τη μορφή, παρουσιάζεται το πρόβλημα.
Όταν στη μέθοδο LoadItems() μετακίνησα το return items; στο τέλος του try block, καθώς και βάζοντας ένα return null στο catch, τότε όλα δούλεψαν κανονικά.
Μην αφήνετε τα media να σας "ταΐζουν"!
|
|
-
09-03-2006, 20:34
|
|
Απ: Επιστροφή nullable αντικειμένου και τα assumptions του .net!
Ο κώδικας κάνει αυτό ακριβώς που του είπες. Με τη new έχεις δημιουργήσει πλήρως τη λίστα. Το items είναι μια πλήρως δημιουργημένη, άδεια λίστα. Αν δεν τροποποιηθεί μέσα στο try, το catch, ή το finally, θα επιστραφεί όπως είναι από τη LoadItems. Δεν υπήρξε σε κανένα σημείο υπόθεση από την πλευρά του runtime. Απλά ο κώδικας όπως γράφτηκε δεν έκανε αυτό που ήθελες.
Αν θέλεις να επιστρέψεις null από τη μέθοδο σε περίπτωση λάθους μπορείς να μην επιστρέφεις τίποτα σε περίπτωση λάθους. Αυτό έκανες όταν μετέφερες την return μέσα στο catch.
Υπάρχει και μια δεύτερη περίπτωση, η οποία μπορεί να φανεί πιο χρήσιμη. Μπορείς να τροποποιήσεις τον υπόλοιπο κώδικα έτσι ώστε να μην διαφοροποιείται η συμπεριφορά του αν η LoadItems επιστρέψει άδεια λίστα. Με τον τρόπο αυτό μπορείς να απλοποιήσεις αρκετά και τον υπόλοιπο κώδικα. Αυτή είναι μια τεχνική γενικής χρήσης η οποία μπορεί να απλοποιήσει σημαντικά τον κώδικα, εξαλείφοντας τα σημεία στα οποία χρειάζεται να κάνεις ελέγχους για null.
Η τεχνική αυτή έχει και όνομα, είναι το Null Object Pattern. Χονδρικά, αντί να επιστρέφεις μια τιμή null επιστρέφεις ένα αντικείμενο το οποίο φέρεται σαν NULL, στην συγκεκριμένη περίπτωση, μια άδεια λίστα. Μία ακόμα βελτίωση που δέχεται η τεχνική είναι, αντί να επιστρέφεις ένα καινούριο άδειο αντικείμενο, να δημιουργήσεις ένα άδειο αντικείμενο σε ένα static readonly field και να επιστρέφεις αυτό όταν χρειάζεται. Έτσι θα αποφύγεις τη δημιουργία πολλαπλών Null objects.
Παναγιώτης Καναβός, Freelancer Twitter: http://www.twitter.com/pkanavos
|
|
-
09-03-2006, 22:18
|
-
Mitsaras
-
-

-
Μέλος από τις 12-09-2005
-
Θεσσαλονίκη
-
Δημοσιεύσεις 818
-
-
|
Απ: Επιστροφή nullable αντικειμένου και τα assumptions του .net!
Παναγιώτη, σ' ευχαριστώ για την απάντηση.
Ορισμένες φορές χρησιμοποιώ τη "λύση της κενής λίστας" (δεν ήξερα ότι ονομάζεται null pattern), ανάλογα και την περίπτωση βέβαια/
Ωστόσο, να ξανατονίσω ότι το "πρόβλημά" (εντός εισαγωγικών, καθώς έχει λυθεί) μου εντοπίζεται αποκλειστικά στο ότι η underlying λίστα έχει δημιουργηθεί, χωρίς να την έχω καλέσει ποτέ. Είναι πολύ σημαντικό αυτό, και το τονίζω. Ούτε τη λίστα έχω καλέσει (που δεν καλείται από πουθενά παρά μόνο από το property), αλλά ούτε και το property! Όντως, η λίστα αυτή καθ' αυτή δεν αλλάζει (μόνο τα περιεχόμενά της).
Το πρόβλημα το διαπίστωσα με τη χρήση του Watch (φυσικά).
Οι υποψίες μου στράφηκαν αμέσως στην μέθοδο του Data Access Tier. Έκανα την αλλαγή που σου περιέγραψα σε ότι αφορά το return αντικείμενο, και έχω πλέον την επιθυμητή συμπεριφορά. Δηλαδή, η λίστα είναι όντως null μέχρι να έρθει η ώρα της πρώτης προσπέλασής της από το property.
Και κάτι πιο μυστήριο; Σε ένα παρόμοιο dictionary τύπου αυτή τη φορά, το αντίστοιχο D.A.T method του που φορτώνει τα δεδομένα, ΔΕΝ βρίσκεται σε try/catch (επειδή μου διέφυγε), ωστόσο είχε τη σωστή συμπεριφορά από την αρχή.
Απολογίες αν τα λέω μπερδεμένα, φταίει η κούραση!
Μην αφήνετε τα media να σας "ταΐζουν"!
|
|
|
|
|