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

 

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

Cast generic classes

Îåêßíçóå áðü ôï ìÝëïò Dimitris Papadimitriou. Τελευταία δημοσίευση από το μέλος pontifikas στις 12-03-2010, 12:55. Υπάρχουν 18 απαντήσεις.
Σελίδα 1 από 2 (19 εγγραφές)   1 2 >
Ταξινόμηση Δημοσιεύσεων: Προηγούμενο Επόμενο
  •  30-01-2009, 12:20 48035

    Cast generic classes

    Έχω μια ερώτηση προς κάποιον syntax expert! Έστω ότι έχουμε τις παρακάτω classes:

    public class Animal { ... }

    public class Lion : Animal { ... }

    public class Tiger : Animal { ... }

    public class Cage<T> where T : Animal
    {
       public void PutFood()
       {
           // do something
       }
    }


    Κάπου στον κώδικα σε άλλο assembly θέλω να έχω πρόσβαση στην PutFood κάπως έτσι (ο κώδικας αυτός πετάει exception αν η παράμετρος είναι τύπου Case<Tiger>):

    void Dummy(Cage<Animal> cage)
    {
       cage.PutFood();
    }


    Για να δουλέψει αυτό πρέπει να γραφτεί έτσι:

    void Dummy(Cage<Animal> cage)
    {
       (cage as Cage<Tiger>).PutFood();
    }


    Το πρόβλημα είναι ότι δεν γνωρίζω από την αρχή τον τύπο του Animal και δεν είναι και τόσο elegant να βγάλω switch για κάθε πιθανό τύπο Animal, καθώς το ζωικό βασίλειο είναι αρκετά πλούσιο!

    Πως λύνεται αυτό ρε παιδιά;
    Σημείωση: Δεν έχω πρόσβαση στον κώδικα των classes που ανέφερα. Έχω πρόσβαση μόνο στον κώδικα της Dummy method.

    Dimitris Papadimitriou
    Software Development Professional
    dotNETZone.gr News

    Οι απαντήσεις παρέχονται για συγκεκριμένες ερωτήσεις και χωρίς καμιά εγγύηση. Διαβάστε επίσης τους όρους χρήσης.
  •  30-01-2009, 12:56 48036 σε απάντηση της 48035

    Απ: Cast generic classes

    Έτσι όπως δίνεις τη δεύτερη Dummy, ούτε αυτή πρέπει να γίνεται compile.

    Υποθέτω ότι υποθέτεις ότι η Cage<Tiger> είναι subclass της Cage<Animal> επειδή η Tiger είναι subclass της Animal. Αυτό όμως δεν ισχύει. Μία κλάση generic δεν ορίζει σχέση inheritance, έτσι η Cage<Tiger> και η Cage<Animal> είναι άσχετες μεταξύ τους.

    Εφόσον η Cage είναι generic κλάση, θα πρέπει να τη χειριστείς σαν τέτοια. Θα πρέπει δηλαδή να γράψεις:

    void Dummy<T>(Cage<T> cage) where T:Animal
    {
        cage.PutFood();
    }

    Έτσι δεν χρειάζεται να κάνεις κανένα cast.


    Παναγιώτης Καναβός, Freelancer
    Twitter: http://www.twitter.com/pkanavos
  •  30-01-2009, 14:34 48039 σε απάντηση της 48036

    Απ: Cast generic classes

    Όντως το generic δεν ορίζει σχέση inheritance και αυτό το πρόβλημα θέλω να ξεπεράσω. Στη λύση που δίνεις πρέπει να γνωρίζω το T declaratively για να καλέσω την Dummy explicitly. Δεν το γνωρίζω όμως. Το γνωρίζω μόνο σαν System.Type. Δηλαδή γνωρίζω από πριν ότι ο τύπος του T είναι Type.GetType("MyAssembly.Tiger, MyAssembly).
    Για κάποιο λόγο νομίζω ότι αυτό που ζητάω δεν γίνεται, απλά ρωτάω μήπως μου ξεφεύγει τίποτα.
    Λέτε να μπορώ να κάνω κάτι με reflection; Όχι πως τελικά μπορώ να το χρησιμοποιήσω, γιατί το θέλω σε σημείο που το performance μετράει, απλά έτσι συζήτηση να γίνεται.

    Dimitris Papadimitriou
    Software Development Professional
    dotNETZone.gr News

    Οι απαντήσεις παρέχονται για συγκεκριμένες ερωτήσεις και χωρίς καμιά εγγύηση. Διαβάστε επίσης τους όρους χρήσης.
  •  30-01-2009, 14:45 48040 σε απάντηση της 48039

    Απ: Cast generic classes

    Η ουσία με τα generics είναι ότι δεν χρειάζεται να ξέρεις τον τύπο. Ο παρακάτω κώδικας τρέχει χωρίς πρόβλημα:
    Cage<Tiger> tigerCage=new Cage<Tiger>();
    Dummy(tigerCage);
    Cage<Lion> lionCage=new Cage<Lion>();
    Dummy(lionCage);


    Η Dummy τρέχει χωρίς κανένα πρόβλημα, άσχετα από το τί τύπος είναι το T.

    Πως προσπαθείς να καλέσεις την Dummy? Μήπως περνάς κάτι περίεργο από το ένα assembly στο άλλο? Μήπως για παράδειγμα περνάς object αντί για Animal, Tiger κλπ? Για δώσε ένα παράδειγμα κλήσης.

    Παναγιώτης Καναβός, Freelancer
    Twitter: http://www.twitter.com/pkanavos
  •  02-02-2009, 12:03 48077 σε απάντηση της 48040

    Απ: Cast generic classes

    Αλήθεια Δημήτρη, τί έγινε με τα generics? Βρήκες λύση?


    Παναγιώτης Καναβός, Freelancer
    Twitter: http://www.twitter.com/pkanavos
  •  02-02-2009, 13:39 48079 σε απάντηση της 48077

    Απ: Cast generic classes

    Δεν νομίζω ότι υπάρχει καλή λύση. Δυστυχώς η Dummy πρέπει να έχει signature Dummy(object) και μέσα σε αυτή ενώ θα έχω μια τιμή που θα έχει όλη την πληροφορία και το functionality που θέλω (PutFood method), ο μόνος τρόπος να την χρησιμοποιήσω είναι το reflection, καθώς δεν μπορώ να κάνω cast. Δεν έχω πρόσβαση να αλλάξω τον κώδικα στα αντικείμενα Animal και Cage, οπότε ο περιορισμός οφείλετε εν μέρη στα semantics (το generic δεν ορίζει σχέση inheritance όπως είπες) και εν μέρη στο σχεδιασμό των αντικειμένων μου (αν η PutFood ήταν σε μια κλάση Cage την οποία κληρονομούσε η Cage<T> τότε όλα θα ήταν μια χαρά).

    Dimitris Papadimitriou
    Software Development Professional
    dotNETZone.gr News

    Οι απαντήσεις παρέχονται για συγκεκριμένες ερωτήσεις και χωρίς καμιά εγγύηση. Διαβάστε επίσης τους όρους χρήσης.
  •  02-02-2009, 14:03 48080 σε απάντηση της 48079

    Απ: Cast generic classes

    Γιατί δεν μπορεί η Dummy να είναι Dummy<T> και πρέπει να είναι Dummy(object)? Εκεί είναι το ζήτημα και όχι στις Animal, Cage. Κάνοντας την Dummy(object) ζητάς συγκεκριμένα από τον compiler να πετάξει οποιαδήποτε πληροφορία έχει για την παράμετρο. Λογικό είναι μετά το μόνο που σου μένει να είναι το Reflection. Γιατί το κάνεις αυτό?

    Υποψιάζομαι ότι το πρόβλημα είναι αλλού και όχι στα generics. Γιατί θέλεις την Dummy(object)? Τί προσπαθείς να κάνεις με αυτή? Καλείται από κώδικα που απαιτεί να είναι object? Κώδικα που δεν ξέρει από Animal? Πρέπει να υλοποιήσει κάποιο συγκεκριμένο interface? Κάτι άλλο?

    Για τις περισσότερες περιπτώσεις υπάρχει λύση, φτάνει να βρούμε ποιά είναι η πραγματική ερώτηση.

    Παναγιώτης Καναβός, Freelancer
    Twitter: http://www.twitter.com/pkanavos
  •  21-02-2009, 01:28 48572 σε απάντηση της 48035

    Απ: Cast generic classes

    Μήπως είναι αυτό που ψάχνεις;

    using System;
    using System.Collections.Generic;
    namespace dokimastiko
    {
        class MainClass
        {
            public static void Main(string[] args)
            {
                Cage<Tiger> tigers = new Cage<Tiger>();
                for(int i =0;i<5;i++)
                {
                    Tiger t = new Tiger();
                    tigers.Add(t);
                }
                tigers.PutFood();
               
                Cage<Horse> horses = new Cage<Horse>();
                for (int i =0;i<5;i++)
                {
                    Horse h = new Horse();
                    horses.Add(h);
                }
                horses.PutFood();
            }
        }
        class Animal
        {
            public Animal(){}
            public string Name;
            public int Age;
            public virtual void PutFood()
            {
             Console.WriteLine("Fae!!!!!!!");   
            }
        }
        class Tiger : Animal
        {
            public override void PutFood ()
            {
                Console.WriteLine("Vale trofi gia tigri!");
            }

        }
        class Horse : Animal
        {
            public override void PutFood ()
            {
                Console.WriteLine("Vale trofi gia Alogo!!");
            }

        }
        class Cage<T> where T : Animal
        {
            private List<T> animals = new List<T>();
            public void Add(T Item)
            {
                animals.Add(Item);
            }
            public void PutFood()
            {
                foreach (Animal a in animals)
                {
                    a.PutFood();
                }
            }
        }
    }

    Iraklis Karagkiozoglou
  •  21-02-2009, 03:01 48573 σε απάντηση της 48572

    Απ: Cast generic classes

    Δεν καταλαβαίνω... Γιατί έχεις βάλει μία List<T>; Έτσι, όπως το έχεις κάνει καλεί την PutFood τόσες φορές όσες και τα ζώα στη λίστα. Δε νομίζω ότι θέλει κάτι τέτοιο. Πιο απλό είναι το:

    using System;
    using System.Collections.Generic;
    using System.Text;

    namespace FeedAnimals
    {
       class Program
       {
          static void Main(string[] args)
          {
             Cage<Tiger> tiger = new Cage<Tiger>();
             tiger.PutFood();
             Cage<Horse> horse = new Cage<Horse>();
             horse.PutFood();
             Cage<Lion> lion = new Cage<Lion>();
             lion.PutFood();
             //
             Console.ReadLine();
          }
       }

       class Animal
       {
          public Animal() { }

          public virtual void PutFood()
          {
             Console.WriteLine("Fae!!!!!!!");
          }

       }

       class Tiger : Animal
       {
          public override void PutFood()
          {
             Console.WriteLine("Vale trofi gia tigri!");
          }
       }

       class Horse : Animal
       {
          public override void PutFood()
          {
             Console.WriteLine("Vale trofi gia Alogo!!");
          }
       }

       class Lion : Animal
       {
          public override void PutFood()
          {
             Console.WriteLine("Vale trofi gia Leontari!!");
          }
       }

       class Cage<T> where T : Animal, new()
       {
          T animal = new T();
          public void PutFood()
          {
             animal.PutFood();
          }
        }

    }

    Το πρόβλημα, όμως, δεν είναι αυτό. Ο Δημήτρης λέει ότι πρόσβαση έχει μόνο στον κώδικα της Dummy. Απ' ό,τι κατάλαβα, δεν έχει πρόσβαση ούτε στις κλάσεις των ζώων, ούτε του Cage. Δημήτρη, τι ακριβώς προσπαθείς να κάνεις; Για τι είδους εφαρμογή πρόκειται; Τα είδη των ζώων είναι γνωστά ή ενδέχεται να προστεθούν κι άλλα στο μέλλον; Και για κάθε είδος ζώου θα φτιάχνεις και κλάση; Δε μου φαίνεται λειτουργικό...


    Ακόμα κι ένας άνθρωπος μπορεί ν' αλλάξει τον κόσμο. Μη θέλεις να κυβερνήσεις. Απλά δείξε το μονοπάτι κι ο κόσμος θ' ακολουθήσει!!
  •  22-02-2009, 14:59 48609 σε απάντηση της 48035

    Απ: Cast generic classes

    Το κοίταξα λίγο περισσότερο και συμφωνώ με τον Παναγιώτη για την Dummy. Εκείνο που με μπερδεύει είναι η Cage. Αν η PutFood εκτελείται μέσα στην Cage, δεν πρέπει να περνάει στον Constructor ή σε Property μια μεταβλητή με το ζώο; Δηλαδή, η υλοποίηση θα πρέπει να είναι κάπως έτσι:

    namespace FeedAnimals
    {
       class Program
       {

          static void Main(string[] args)
          {
             MyClass myClass = new MyClass();
             //
             Cage<Tiger> tigerCage = new Cage<Tiger>(new Tiger());
             Cage<Lion> lionCage = new Cage<Lion>(new Lion());
             Cage<Horse> horseCage = new Cage<Horse>(new Horse());
             //
             // Ή το παραπάνω ή αυτό:
             //
             //Cage<Tiger> tigerCage = new Cage<Tiger>();
             //tigerCage.Animal = new Tiger();
             //Cage<Lion> lionCage = new Cage<Lion>();
             //lionCage.Animal = new Lion();
             //Cage<Horse> horseCage = new Cage<Horse>();
             //horseCage.Animal = new Horse();
             //
             myClass.Dummy(tigerCage);
             myClass.Dummy(lionCage);
             myClass.Dummy(horseCage);
             //
             Console.ReadLine();
          }
       }

       class MyClass
       {
          public void Dummy<T>(Cage<T> animalCage) where T : Animal
          {
             animalCage.PutFood();
          }
       }

       class Cage<T> where T : Animal
       {
          private T animal;

          public T Animal
          {
             get { return animal; }
             set { animal = value; }
          }

          public Cage(T animal)
          {
             this.animal = animal;
          }

          public Cage() { }

          public void PutFood()
          {
             if (animal is Lion)
             {
                Console.WriteLine("Vale trofi gia Leontari!!");
             }
             else if (animal is Tiger)
             {
                Console.WriteLine("Vale trofi gia tigri!");
             }
             else if (animal is Horse)
             {
                Console.WriteLine("Vale trofi gia Alogo!!");
             }
          }
       }

       class Animal
       {
          public Animal() { }
       }

       class Tiger : Animal
       {
       }

       class Horse : Animal
       {
       }

       class Lion : Animal
       {
       }

    }

    Μου διαφεύγει κάτι;


    Ακόμα κι ένας άνθρωπος μπορεί ν' αλλάξει τον κόσμο. Μη θέλεις να κυβερνήσεις. Απλά δείξε το μονοπάτι κι ο κόσμος θ' ακολουθήσει!!
  •  22-02-2009, 15:39 48610 σε απάντηση της 48609

    Απ: Cast generic classes

    Sorry, stupid of me...

    Η Cage μπορεί να είναι κι έτσι:

    class Cage<T> where T : Animal
    {

       public void PutFood()
       {
          if (this is Cage<Lion>)
          {
             Console.WriteLine("Vale trofi gia Leontari!!");
          }
          else if (this is Cage<Tiger>)
          {
             Console.WriteLine("Vale trofi gia tigri!");
          }
          else if (this is Cage<Horse>)
          {
             Console.WriteLine("Vale trofi gia Alogo!!");
          }
       }

    }


    Ακόμα κι ένας άνθρωπος μπορεί ν' αλλάξει τον κόσμο. Μη θέλεις να κυβερνήσεις. Απλά δείξε το μονοπάτι κι ο κόσμος θ' ακολουθήσει!!
  •  22-02-2009, 22:27 48627 σε απάντηση της 48610

    Απ: Cast generic classes

    Αν είναι να βάλεις type checking μέσα στην Cage, αχρήστεψες τα generics. Τα type-checks δεν είναι διευκόλυνση, είναι ακριβώς αυτό που ζητάμε να αποφύγουμε. Ακόμα και χωρίς generics θα μπορούσες να αποφύγεις τα type-checks απλός δημιουργώντας διαφορετικά overrides για κάθε ζώο. Τα generics σου επιτρέπουν να παρακάμψεις ακόμα και αυτό.

    Αυτό που πρότεινε ο ikaragkiozoglou (κάπως ... περιφραστικά) δεν είναι άσχημο, να μεταφερθεί δηλαδή η PutFood από την Cage στην κάθε Animal. Ο Δημήτρης όμως δεν μας έχει πει ακόμα τί ψάχνει, οπότε η συζήτηση "αυτό βολεύει" ή "το άλλο βολεύει" δεν βγάζει πουθενά απλά γιατί .... δεν ξέρουμε την ερώτηση! Αν μάλιστα σκεφτούμε ότι ο Δημήτρης δεν ρώτησε τί να κάνει την PutFood, αλλά μία άλλη Dummy, το να πειράζουμε την PutFood δεν φαίνεται να βοηθάει.

    Δημήτρη, περιμένουμε ακόμα να μας πεις γιατί πρέπει αντί για Dummy<T> να χρησιμοποιήσεις Dummy(object)!


    Παναγιώτης Καναβός, Freelancer
    Twitter: http://www.twitter.com/pkanavos
  •  22-02-2009, 22:34 48628 σε απάντηση της 48627

    Απ: Cast generic classes

    Αφού ο Δημήτρης λέει ότι δεν έχει πρόσβαση στον κώδικα της Cage, της Animal κ.λπ.!! Άν μπορεί να μπουν PutFood() methods στις κλάσεις των ζώων, ποιος ο λόγος να καλέσω την Cage;

    Όσο για το type checking στο generic συμφωνώ. Με τα signatures που έδωσε ο Δημήτρης υπάρχει τρόπος να υλοποιηθεί διαφορετικά; Τι να κάνω; Το ψάχνω στα τυφλά!!


    Ακόμα κι ένας άνθρωπος μπορεί ν' αλλάξει τον κόσμο. Μη θέλεις να κυβερνήσεις. Απλά δείξε το μονοπάτι κι ο κόσμος θ' ακολουθήσει!!
  •  22-02-2009, 22:45 48630 σε απάντηση της 48628

    Απ: Cast generic classes

    Ευχαριστώ όλους για τη συμμετοχή!
    Όλα όσα έχω αναφέρει στο αρχικό μου post νομίζω ότι περιγράφουν το πρόβλημα. Το μόνο που ίσως πρέπει να προσθέσω ότι το signature της Dummy δεν μπορεί να έχει generic καθώς δεν ξέρω εκ των προτέρων τον τύπο που θα περάσει κανείς. Μπορεί να είναι Dummy(object) ή Dummy(Cage).
    Όντως η μόνη λύση που βλέπω είναι αυτή που δίνει ο Markos αλλά φυσικά το switch σκοτώνει την όλη ιδέα καθώς δεν μπορώ να ξέρω από την αρχή όλους τους τύπους Animal.
    Ίσως υπάρχει μια δεύτερη λύση με reflection και κάποιο Invoke με όλα του τα μειονεκτήματα. Λέτε;

    Dimitris Papadimitriou
    Software Development Professional
    dotNETZone.gr News

    Οι απαντήσεις παρέχονται για συγκεκριμένες ερωτήσεις και χωρίς καμιά εγγύηση. Διαβάστε επίσης τους όρους χρήσης.
  •  22-02-2009, 22:49 48631 σε απάντηση της 48630

    Απ: Cast generic classes

    Μάλλον δυσκολεύομαι να περιγράψω το πρόβλημα... το παραδέχομαι! Smile

    Dimitris Papadimitriou
    Software Development Professional
    dotNETZone.gr News

    Οι απαντήσεις παρέχονται για συγκεκριμένες ερωτήσεις και χωρίς καμιά εγγύηση. Διαβάστε επίσης τους όρους χρήσης.
Σελίδα 1 από 2 (19 εγγραφές)   1 2 >
Προβολή Τροφοδοσίας RSS με μορφή XML
Με χρήση του Community Server (Commercial Edition), από την Telligent Systems