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

 

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

Πρόβλημα κατά την προσθήκη derived-class objects σε generic collection(of BaseClass)

Îåêßíçóå áðü ôï ìÝëïò Sunburn. Τελευταία δημοσίευση από το μέλος Sunburn στις 08-01-2008, 10:37. Υπάρχουν 8 απαντήσεις.
Ταξινόμηση Δημοσιεύσεων: Προηγούμενο Επόμενο
  •  07-01-2008, 10:34 38838

    Πρόβλημα κατά την προσθήκη derived-class objects σε generic collection(of BaseClass)

    Ενα ελαφρώς ακανθώδες πρόβλημα...

    Έχω την baseclass:


    Public Class ActiveUnit
    Inherits Unit

    Public Navigator As ActiveUnit_Navigator
    Public AI As ActiveUnit_AI
    Public Kinematics As ActiveUnit_Kinematics
    Public Sensory As ActiveUnit_Sensory

    end class



    Από αυτήν κατάγεται η derived class Platform:

    Public Class Platform

    Inherits ActiveUnit

    '...some other properties here

    end class



    Και επίσης διάφορες derived classes από αυτήν, πχ:

    Public Class Aircraft
    Inherits Platform

    Public Shadows Navigator As Aircraft_Navigator
    Public Shadows AI As Aircraft_AI
    Public Shadows Kinematics As Aircraft_Kinematics

    end class


    Public Class Ship

    Inherits Platform

    Public Shadows Navigator As Ship_Navigator
    Public Shadows AI As Ship_AI
    Public Shadows Kinematics As Ship_Kinematics

    end class


    και ούτω καθεξής. (Το Aircraft_Navigator και το Ship_Navigator κληρονομούν το ActiveUnit_Navigator, και αντίστοιχα ομοίως για το ΑΙ & Kinematics).

    Ο λόγος που χρησιμοποιώ Shadows είναι οτι πρόκειται να δημιουργήσω μια σειρά από aircraft και ship objects και να τα τοποθετήσω  σε μια collection(of ActiveUnit). Ετσι ωστε μετά, όταν θέλω κάθε αντικείμενο να κάνει τις δικές του ενέργειες, να καλώ π.χ:

    For each theUnit as ActiveUnit in UnitCollection
        theUnit.Navigator.PlotCourse
    next

    ...και κάθε object να χρησιμοποιεί τον δικό του Navigator αντί αυτού της ActiveUnit.

    Δημιουργώ λοιπόν ένα καινούργιο object, ας πούμε ένα aircraft, και όλα τα properties του δημιουργούνται κανονικά. Το προσθέτω στο UnitCollection..... και ακριβώς πάνω στην ένταξή του όλα τα properties Navigator, AI & Kinematics μηδενίζονται! (γίνονται Nothing). ('Αλλα  properties που είναι strings, integers  κλπ.  παραμένουν αναλλοίωτα).

    _Υποθέτω_ πως αυτό γίνεται επειδή το UnitCollection περιμένει να του προστεθούν αντικέιμενα ActiveUnit, των οποίων το Navigator να είναι τύπου ActiveUnit_Navigator κ.ο.κ. και όταν βλέπει οτι του έρχεται αντικείμενο που είναι μεν derived από ActiveUnit αλλά τα complex properties του δεν έιναι ActiveUnit_Navigator κλπ., τα απορρίπτει ως "ξένα".

    Αυτό όμως δεν είναι λιγο κουφο; Αφου τα complex properties του κάθε αντικειμένου (δηλ. τα Navigator, AI & Kinematics) ειναι derived απο τα complex properties του baseclass (ActiveUnit), δεν θα έπρεπε το UnitCollection  να τα δεχτεί αδιαμαρτήρητα; Ποιά η χρησιμότητα των generic collections αν δεν μπορούμε να προσθέσουμε σε αυτές derived objects με derived complex properties;

    Κάθε ιδέα προς επίλυση αυτού το προβλήματος καλοδεχούμενη....
  •  07-01-2008, 11:17 38840 σε απάντηση της 38838

    Απ: Πρόβλημα κατά την προσθήκη derived-class objects σε generic collection(of BaseClass)

    Υπάρχουν διάφορα θέματα με την υλοποίησή σου. Κατ' αρχήν, έχεις ορίσει τα μέλη της κλάσης σου σαν public πεδία και όχι properties, κάτι που σε περιορίζει πάρα πολύ, και ιδιαίτερα στο ότι δεν μπορείς με αυτό τον τρόπο να ορίσεις πολυμορφική συμπεριφορά στα object σου. Έτσι καταλήγεις να χρησιμοποιείς το Shadows, που δεν είναι και πολύ καλή πρακτική.

    Θα ήταν προτιμότερο η base class σου να είναι κάπως έτσι:

    Public Class ActiveUnit
    Inherits Unit

    Public Overridable Property Navigator() As ActiveUnit_Navigator
    ...
    End Property
    Public Overridable Property AI() As ActiveUnit_AI
    ...
    End Property
    Public Overridable Property Kinematics() As ActiveUnit_Kinematics
    ...
    End Property
    Public Overridable Property Sensory() As ActiveUnit_Sensory
    ...
    End Property
    End Class

    και να κάνεις override τα properties στις derived κλάσεις ώστε να επιστρέφουν αντικείμενο του σωστού τύπου (π.χ. Aircraft_Navigator).

    Αντίστοιχα η ActiveUnit_Navigator θα έχει μια Overridable Sub PlotCourse() την οποία η Aircraft_Navigator θα κάνει override με τη σωστή υλοποίηση κλπ.

    Και μια τελευταία παρατήρηση: τα underscores σε ονόματα κλάσεων είναι bad practice, αν περάσεις το project σου από τον FxCop θα διαμαρτυρηθεί.


    Νατάσα Μανουσοπούλου
  •  07-01-2008, 11:24 38841 σε απάντηση της 38838

    Απ: Πρόβλημα κατά την προσθήκη derived-class objects σε generic collection(of BaseClass)

    'Εκανα ενα δευτερο τεστ: Ξανα, δημιούργησα ενα aircraft object και το πρόσθεσα στην UnitCollection, που είναι Collection(of ActiveUnit).

    For each theUnit As ActiveUnit in UnitCollection.....

    Return Ctype(theUnit, Aircraft).Navigator => Aircraft_Navigator object (σωστά, όπως πρέπει).

    Return theUnit.Navigator => Nothing

    Όταν λοιπόν γίνεται explicit casting στον τύπο Aircraft, μας επιστρέφει το aircraft_navigator object που θέλουμε. Το θέμα ειναι, πώς θα γίνει να επιστρέφει το επιθημητό object ΧΩΡΙΣ να χρειαστεί να γίνει explicit cast (αφου όταν κάνουμε enumeration στο UnitCollection δεν μπορούμε να ξέρουμε εκ των προτέρων αν το κάθε  αντικείμενο έιναι  aircraft ή ship ή οτιδήποτε άλλο, ξέρουμε μόνο ότι είναι σίγουρα ActiveUnit).
     
  •  07-01-2008, 11:49 38843 σε απάντηση της 38840

    Απ: Πρόβλημα κατά την προσθήκη derived-class objects σε generic collection(of BaseClass)

    Νατάσα Μανουσοπούλου:

    Υπάρχουν διάφορα θέματα με την υλοποίησή σου. Κατ' αρχήν, έχεις ορίσει τα μέλη της κλάσης σου σαν public πεδία και όχι properties, κάτι που σε περιορίζει πάρα πολύ, και ιδιαίτερα στο ότι δεν μπορείς με αυτό τον τρόπο να ορίσεις πολυμορφική συμπεριφορά στα object σου. Έτσι καταλήγεις να χρησιμοποιείς το Shadows, που δεν είναι και πολύ καλή πρακτική.

    Θα ήταν προτιμότερο η base class σου να είναι κάπως έτσι:

    Public Class ActiveUnit
    Inherits Unit

    Public Overridable Property Navigator() As ActiveUnit_Navigator
    ...
    End Property
    Public Overridable Property AI() As ActiveUnit_AI
    ...
    End Property
    Public Overridable Property Kinematics() As ActiveUnit_Kinematics
    ...
    End Property
    Public Overridable Property Sensory() As ActiveUnit_Sensory
    ...
    End Property
    End Class

    και να κάνεις override τα properties στις derived κλάσεις ώστε να επιστρέφουν αντικείμενο του σωστού τύπου (π.χ. Aircraft_Navigator).


    Σε όλα τα παραδείγματα που έχω δει για την χρήση του "Property", το μέλος που γίνεται Get/Set είναι simple type π.χ. string, integer κλπ. Στην περίπτωσή μου, το ActiveUnit_Navigator κ.ο.κ. είναι full-fledged class με δικά του properties, functions etc. (Αρχικά ήταν όλα μαζί στο class ActiveUnit αλλά τα μετακίνησα σε ξεχωριστά classes γιατι λόγω μεγέθους η συντήρηση είχε αρχίσει να γίνεται δύσκολη).

    Πώς γίνεται το Get/Set του Property να διαχειριστεί ένα complex type;

    Νατάσα Μανουσοπούλου:
    Αντίστοιχα η ActiveUnit_Navigator θα έχει μια Overridable Sub PlotCourse() την οποία η Aircraft_Navigator θα κάνει override με τη σωστή υλοποίηση κλπ.

    Αυτό ακριβώς έχω κάνει. Ο λόγος που κάθε ActiveUnit-derived class έχει δικά της Navigator, AI, Kinematics κλπ. (τα οποία με τη σειρά τους ειναι  derived από το ActiveUnit_Navigator etc.) είναι ώστε κάθε αντικείμενο να μπορεί να κάνει override τις default (ActiveUnit) μεθόδους με τις δικές του όποτε χρειαστεί.

  •  07-01-2008, 12:05 38844 σε απάντηση της 38843

    Απ: Πρόβλημα κατά την προσθήκη derived-class objects σε generic collection(of BaseClass)

    Sunburn:

    Σε όλα τα παραδείγματα που έχω δει για την χρήση του "Property", το μέλος που γίνεται Get/Set είναι simple type π.χ. string, integer κλπ. Στην περίπτωσή μου, το ActiveUnit_Navigator κ.ο.κ. είναι full-fledged class με δικά του properties, functions etc. (Αρχικά ήταν όλα μαζί στο class ActiveUnit αλλά τα μετακίνησα σε ξεχωριστά classes γιατι λόγω μεγέθους η συντήρηση είχε αρχίσει να γίνεται δύσκολη).

    Πώς γίνεται το Get/Set του Property να διαχειριστεί ένα complex type;

     

    "οπως και για primitives:

    Public override Property Navigator() As ActiveUnit_Navigator

    Get

    Return _Navigator

    End Get

    Set(ByVal value As ActiveUnit_Navigator )

    _Navigator= value

    End Set

    End Property

     

    Και στο return μπορείς να κάνεις Navigator().MethodOrProperty Call

    Hope that helped

    Nassos

    PS. Επιδή ειμαι C# Developer και οι γνώσεις μου στην VB ειναι terrible! μπορει το "override" να μην δουλεψει ετσι όπως το συνταξα.


    "Success is the ability to go from one failure to another with no loss of enthusiasm."
    Winston Churchill

    "Quality means doing it right when no one is looking."
    Henry Ford

  •  07-01-2008, 12:48 38849 σε απάντηση της 38844

    Απ: Πρόβλημα κατά την προσθήκη derived-class objects σε generic collection(of BaseClass)

    Πραγματικά αυτή είναι η λύση. Σας ευχαριστώ αμφότερους.
  •  07-01-2008, 17:29 38877 σε απάντηση της 38849

    Απ: Πρόβλημα κατά την προσθήκη derived-class objects σε generic collection(of BaseClass)

    Δυστυχώς φάινεται πως το πρόβλημα παραμένει, σε διαφορετική μορφή.

    Ακολουθώντας την ανωτέρω συμβουλή, μετέτρεψα τα complex type πεδία (Navigator, AI, Kinematics κλπ.) σε Get/Set properties, τόσο στην baseclass ActiveUnit όσο και σε όλες τις derived classes. Ωστόσο, τώρα παρουσιάζεται το εξής Catch-22:

    * Αν ορίσω π.χ. το property "Navigator" στην class "Aircraft" να δέχεται και να επιστρέφει αντικείμενο τύπου Aircraft_Navigator (που έιναι το επιθυμητό), καθως και να κάνει override το αντίστοιχο property "Navigator" της class "ActiveUnit" (το οποίο επιστρέφει αντικείμενο ActiveUnit_Navigator), o compiler γκρινάζει οτι δεν μπορεί να δεχτει το override γιατι τα δυο properties επιστρέφουν διαφορετικά Object types.

    * Αν, αντί για override, ορίσω το property "Navigator" στην class "Aircraft" να κάνει overload το αντίστοιχο property "Navigator" της class "ActiveUnit" (ωστε να επιστρέφει και να δέχεται Aircraft_Navigator objects), ο compiler το δέχεται. Ωστόσο, στην εκτέλεση του προγράμματος και την προσπέλαση του loop "For each theUnit as ActiveUnit in UnitCollection....", o κώδικας εκτελεί την εντολή PlotCourse _στο ActiveUnit_Navigator_ παρολο που υπάρχει αντίστοιχη μέθοδος στο Aircraft_Navigator (η οποια φυσικά κανει override την αντίστοιχη του ActiveUnit_Navigator). Υποθέτω πως αυτό γίνεται επειδή στο loop enumeration δηλώνω το αντικείμενο ως "ActiveUnit" αντί για "Aircraft", οπότε το πρόγραμμα πάει κετευθείαν στην baseclass και αγνοεί οποιοδήποτε overloading υπάρχει στις derived classes.

    Μπρος γκρεμός και πίσω ρέμα λοιπόν. Ή δηλώνω override (που είναι αυτό που ουσιαστικά θέλω) και ο compiler χτυπάει άκυρο λόγω του type mismatch, ή δηλωνω overload και χάνω την επιθυμητή λειτουργικότητα.

    Όπως πριν, κάθε πρόταση λύσης ευπρόσδεκτη.
  •  07-01-2008, 17:47 38881 σε απάντηση της 38877

    Απ: Πρόβλημα κατά την προσθήκη derived-class objects σε generic collection(of BaseClass)

    Sunburn:
    * Αν ορίσω π.χ. το property "Navigator" στην class "Aircraft" να δέχεται και να επιστρέφει αντικείμενο τύπου Aircraft_Navigator (που έιναι το επιθυμητό), καθως και να κάνει override το αντίστοιχο property "Navigator" της class "ActiveUnit" (το οποίο επιστρέφει αντικείμενο ActiveUnit_Navigator), o compiler γκρινάζει οτι δεν μπορεί να δεχτει το override γιατι τα δυο properties επιστρέφουν διαφορετικά Object types.

    ΟΧΙ  στην Class Aircraft το property θα δέχετε και θα επιστρέφει ActiveUnit_Navigator μέσα στο Get/Set του Property θα εσύ θα κάνει return το Aircraft_Navigator του class σου ο compiler δεν θα χτυπήσει γιατί η Aircraft_Navigator είναι τύπου ActiveUnit_Navigator!!!!

    τό ίδιο σε όλες τις Classes που κληρονομούν από το ActiveUnit_Navigator θα κάνεις το ίδιο!! Ο Compiler ξέρει το Underline Τype του ActiveUnit_Navigator (Aircraft_Navigator,κτλ) και θα τρέξει το σωστό implementation.

    [EDIT]: Μπορείς να κάνεις Cast πχ

    Aircraft craft1 = new Aircraft ();
    Aircraft_Navigator craftNav = (Aircraft_Navigator)craft.Navigator ;

    sory for the C#

    Hope that helped

    Nassos


    "Success is the ability to go from one failure to another with no loss of enthusiasm."
    Winston Churchill

    "Quality means doing it right when no one is looking."
    Henry Ford

  •  08-01-2008, 10:37 38905 σε απάντηση της 38881

    Απ: Πρόβλημα κατά την προσθήκη derived-class objects σε generic collection(of BaseClass)

    'Εχεις δίκιο. 'Ηταν δική μου γκάφα στο αρχικό implementation. Πολλές ευχαριστίες.


Προβολή Τροφοδοσίας RSS με μορφή XML
Με χρήση του Community Server (Commercial Edition), από την Telligent Systems