Reflection, part Two

Αυτό το post είναι μέρος μιας τετράδας από blog posts σχετικά με το reflection. Δείτε τα υπόλοιπα εδώ

Στο προηγούμενο blog post αναφερθήκαμε σχετικά με τι είναι γενικά το reflection, και πως μπορούμε να πάρουμε διάφορες πληροροφίες από μία assembly κατά το runtime. Σε αυτό, θα δούμε πως μπορούμε να πάρουμε πληροφορίες για διάφορα types και να κάνουμε reflection πάνω σε αυτά.

  

Getting Types

Υπάρχουν διάφοροι τρόποι για να πάρουμε types.

  • Μπορούμε να πάρουμε τα types μιας assembly
  • Μπορούμε να πάρουμε τα types ενός module
  • Μπορούμε να πάρουμε τα types κάποιου instance ενός object
  • Μπορούμε να χρησιμοποιήσουμε τα keywords typeof (C#) και GetType (Visual Basic)

Όταν εργαζόμαστε με μία assembly, μπορούμε να πάρουμε τα Types της με χρήση της GetTypes() συνάρτησης. Η ίδια μέθοδος υπάρχει και στο αντικείμενο Module.

image

Επίσης, μπορούμε να πάρουμε το Type ενός instance ενός αντικειμένου, με την GetType μέθοδο (την κληρονομεί από το System.Object)

image

Επίσης, μπορούμε να δημιουργήσουμε ένα Type από ένα value type ή ένα reference type με τη χρήση της typeof keyword (GetType στη VB)

image

Το αντικείμενο Type έχει πολλά μέλη (συναρτήσεις, properties κ.λ.π.) τα οποία μπορείτε να τα δείτε εδώ. Μερικές πληροφορίες που μπορούμε να πάρουμε για ένα instance ενός Type είναι το namespace του, το όνομά του, αν είναι ValueType (όπως τα int, float, double, κάποιο structure κ.λ.π.), αν είναι Public κ.λ.π. Δείτε τον παρακάτω κώδικα για μερικές από τις πληροφορίες που μπορούμε να πάρουμε

image

Επιπροσθέτως, με τον ίδιο τρόπο που μπορούμε να εξετάσουμε για attributes σε μία assembly, μπορούμε να εξετάσουμε και για attributes σε ένα Type

image

Η διαφορά ανάμεσα στην GetCustomAttributes όταν εκτελείται σε assembly και όταν εκτελείται σε Type, είναι πως η boolean παράμετρος ενώ αγνοείται όταν γίνεται κλήση από assembly, εδώ δεν αγνοείται. Η χρησιμότητά της είναι ότι “λέει” στην GetCustomAttributes να κοιτάξει στην κλάση που αντιπροσωπεύει το instance του Type και για attributes που γίνονται inherit από μία γονική κλάση.

Σημείωση

Έστω ότι έχουμε τα εξής
image 
Έτσι και εκτελέσουμε τον παρακάτω κώδικα
image
το αποτέλεσμα θα είναι
image
Γιατί; Επειδή ένα αντικείμενο είναι πάντα ενός τύπου. Μπορεί να γίνει cast σε μία γονική κλάση ή σε ένα Interface που υλοποιεί, αλλά ο τύπος του δεν αλλάζει.

Enumerating Class members

Στην κλάση Type υπάρχουνε μέθοδοι για να πάρουμε διαφορετικά μέρη ενός Type (μεθόδους, properties, fields, events κ.α.). Κάθε ένα από αυτά τα μέρη αντιπροσωπεύεται στο Framework από μία κλάση που το όνομά της τελειώνει με τη λέξη Info. Έτσι λοιπόν, η κλάση που αντιπροσωπεύει μια μέθοδο λέγεται MethodInfo, η κλάση που αντιπροσωπεύει ένα Event λέγεται EventInfo, κ.λ.π. Όλες αυτές οι κλάσεις παράγονται από μία γονική, που ονομάζεται MemberInfo (αυτή την κλάση κληρονομεί και το Type αντικείμενο). Στην κλάση MemberInfo υπάρχουν κάποιες κοινές μέθοδοι για διάφορες πληροφορίες, ενώ οι σημαντικές πληροφορίες υπάρχουνε στις κλάσεις “απογόνους”. Οι συναρτήσεις για να πάρουμε instances αυτών των κλάσεων από ένα Type ακολουθούν την ονοματοδοσία Get + Event|Method|Field|Property κ.α. Στο τέλος μπορεί να υπάρχει και η κατάληξη s, για να μας επιστραφεί ένας πίνακας από objects.

Για παράδειγμα, για να βρούμε όλα τα methods σε μία κλάση κάνουμε το εξής

 image

Βλέπουμε ότι μπορούμε να πάρουμε το όνομα κάθε συνάρτησης, το όνομα της επιστρεφόμενης τιμής της, καθώς και όλα τα ονόματα των παραμέτρων της.

Είναι πολύ εύκολο επίσης να δούμε και τα Nested Types

image

αλλά και τα Members γενικά

image 

Βέβαια, όσο κάνουμε enumerate τα MemberInfo, μπορούμε να δούμε και αν κάποιο από αυτά είναι κάποιου συγκεκριμένου τύπου, κάνοντας χρήση του MemberTypes enumeration

image

Το MethodBody

Για να πάρουμε τον IL κώδικα μιας μεθόδου, χρησιμοποιούμε το MethodBody αντικείμενο (επιστρέφεται από τη συνάρτηση GetMethodBody, η οποία υπάρχει στις κλάσεις ConstructorInfo ή MethodInfo).

Δείτε εδώ πως μπορούμε να δούμε τις τοπικές μεταβλητές μιας συνάρτησης αλλά και πως μπορούμε να πάρουμε τον IL κώδικα της συνάρτησης σε έναν πίνακα από bytes.

image

BindingFlags

Το enumeration BIndingFlags χρησιμοποιείται για να ελέγξει πως κάποια members ενός Type λαμβάνονται κατά τη χρήση της GetMembers μεθόδου. Είναι ένα flagged enumeration, πράγμα το οποίο σημαίνει ότι δύο ή περισσότερα μέλη της μπορούν να χρησιμοποιηθούν ταυτόχρονα.

Τα μέλη του BindingFlags enumeration είναι

  • DeclaredOnly : αγνοούνται τα inherited members
  • Default : Δεν χρησιμοποιείται κάποιο BindingFlag
  • FlattenHierarchy : Επιστρέφει declared, inherited αλλά και protected members
  • IgnoreCase : Αγνοείται το casing (πεζά – κεφαλαία) κατά το ταίριασμα του ονόματος
  • Instance : Επιστρέφονται τα μέλη του instance του type
  • NonPublic : Επιστρέφει protected, internal και private μέλη
  • Public : Επιστρέφει τα public μέλη
  • Static : Επιστρέφει τα static μέλη

Δείτε τον παρακάτω κώδικα

image

Ο μέχρι τώρα κώδικας επισυνάπτεται στο παρόν post.

Στο επόμενο blog post θα δούμε την χρήση κώδικα από assemblies που γίνονται reflected στο runtime.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s