Γενικά, το FxCop είναι φοβερό εργαλείο. Ειδικά στον έλεγχο για τον σωστό ορισμό του IDisposable κυριολεκτικά καταλαβαίνει τί κάνει ο κώδικας σου και σου βρίσκει τα λάθη. Το περίεργο είναι ότι μερικά από αυτά τα λάθη τα βρίσκει στον generated κώδικα των typed datases, services κλπ!
Γενικά, η κλάση Dispose χρησιμεύει για να καθαρίζει είτε unmanaged είτε ακριβά resources, όπως ένα connection, ένα stream, μεγάλους πίνακες κλπ, τα οποία θέλεις να ελέγχεις πότε θα ελευθερωθούν. Επειδή όμως άλλο το dispose λόγω finalization και άλλο επειδή κάλεσες την dispose, χρειάζεσαι δύο overloads της dispose. Η μία παίρνει σαν παράμετρο το isDisposing που ειδοποιεί για το αν το dispose γίνεται λόγω finalization ή επειδή κάλεσες την Dispose. Η διαφορά είναι ότι όταν γίνεται finalization δεν ξέρεις αν τα πεδία της κλάσης έχουν υπαρκτά αντικείμενα ή έχουν ήδη γίνει finalize! Μπορεί π.χ. να πας εσύ να κάνεις dispose ένα stream και αυτό να έχει ήδη γίνει disposed. Γι αυτό, η Dispose(bool) έχει ένα if το οποίο καλεί την Dispose του κάθε πεδίου αν έχει τιμή true. Για τα unmanaged resources δεν ισχύει αυτό, και πάντα τα κλείνεις/σβήνεις έξω από το if. Πέρα από αυτό, η απλή Dispose() καλεί την Dispose(true) ενώ ο finalizer την Dispose(false).
Άλλη σημαντική λεπτομέρεια, είναι ότι η Dispose(bool) πρέπει να είναι protected virtual για να μπορούν οι child κλάσεις να κάνουν override και να προσθέσουν τον δικό τους κώδικα για dispose. Τελευταία λεπτομέρεια, είναι ότι τελειώνοντας η Dispose() πρέπει να καλέσει την GC.SuppressFinalize, για να ειδοποιήσει το .NET ότι έχει ήδη γίνει το dispose, και να μην ξανακαλέσει τον finalizer. Τέλος, για να αποφευχθούν προβλήματα του στυλ καλώ δύο φορές την Dispose, η Dispose(bool) ελέγχει ένα πεδίο, το disposed ή _disposed ή όπως θέλεις να το πεις, σε true και τερματίζει αμέσως αν το βρει true. Αλλιώς, όταν τελειώσει το θέτει true.
Και το FxCop τα ελέγχει όλα αυτά!
Ο λόγος τώρα που σου βγάζει warnings σε κάποια generated datatables, services κλπ και δεν σου το βγάζει σε απλά datatables είναι ότι τα typed datatables ή τα services είναι ουσιαστικά απλές κλάσεις. Επειδή συνήθως αυτές οι κλάσεις δεν περιέχουν επιπλέον πεδία, ο generated κώδικας για το dispose δεν υλοποιεί όλες τις λεπτομέρεις. Το FxCop όμως δεν μπορεί να ξέρει αν η κλάση περιέχει πεδία που κρατάνε unmanaged ή ακριβά resources, γι αυτό σε ειδοποιεί. Μπορείς να αγνοήσεις αυτή την ειδοποίηση ή να τροποποιήσεις την Dispose των Datatable για να μην γκρινιάζει το FxCop.
Είχα διαβάσει και εγώ αρκετά πράγματα για το πως φτιάχνει κανείς ένα σωστό Dispose, αλλά το κατάλαβα πραγματικά όταν άρχισα να διορθώνω τα warnings του FxCop. Δεν είναι υπερβολή να πω ότι το σωστό IDisposable το έμαθα από το FxCop!
Παναγιώτης Καναβός, Freelancer
Twitter: http://www.twitter.com/pkanavos