• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Dziedziczenie w C# - sprawdzanie zgodności typów

VPS Starter Arubacloud
0 głosów
228 wizyt
pytanie zadane 26 marca 2017 w C# przez Adam Olesiak Gaduła (3,290 p.)

Cześć,

Zacząłem trochę bawić się polimorfizmem w C# i mam taką sytuację, z którą nie mogę dojść do porozumienia:

Mam klasę JetpackSpot, w której mam taką metodę(zadaniem metody jest sprawdzić czy dany przedmiot może zostać wstawiony do tej konkretnej instancji spota na przedmiot):

public override bool putItemIn(Item itemToPut)
    {
        //Klasa Jetpack dziedziczy po klasie Item
        if (itemToPut is Jetpack)
        //dalszy kod

 

Ogólnie fajnie i działa, ale taką samą metodę musiałem wrzucić do kilku innych klas dziedziczących z InventorySpot(tj. BootsSpot, SuitSpot, WeaponSpot) - jedyną różnicą jest ten if sprawdzający zgodność typów.

W jaki sposób mogę określić nazwę konkretnej klasy jako argument dla innej klasy. Tak żeby potem sprawdzać tylko if(itemToPut is RequiredClassName)?

1
komentarz 26 marca 2017 przez rafal.budzis Szeryf (85,260 p.)

If jest dobrym rozwiązaniem nie wiem co rozumiesz poprzez dalszy kod bo powinna być tam jedna linijka która wywoła funkcje z klasy bazowej ;) To wcale nie jest złe rozwiązanie ;)

public override bool putItemIn(Item itemToPut)
{
    if (itemToPut is Jetpack){
        base.putItemIn(itemToPut);
    }
}



 

1
komentarz 26 marca 2017 przez NowyUrzydgownig Mądrala (5,090 p.)
Rozumiem, że masz klasę main, a poniej kilka kas dziedziczących. Sprawdzasz, więc w ten sam sposób. Jeżeli masz utworzoną referencje klasy main, a następnie tworzysz instancję rzutując w górę z klasy pochodnej, to możesz sprawdzić dokładnie w ten sam sposób. Czyli main is klasaPochodna.
komentarz 26 marca 2017 przez Adam Olesiak Gaduła (3,290 p.)
edycja 26 marca 2017 przez Adam Olesiak

Kurczę, trochę mi głupio, że usunąłem tą linijkę z base.putItemIn, bo nie wiedziałem co robi..
W każdym razie podoba mi się to rozwiązanie. Zaimplementowałem je, ale nadal jest trochę copy paste:

Jedyne co zmieniam w innych klasach to słowa zaznaczone na czerwono na (SuitSpot, Suit, suit,Suit) - edit: kolor nie działa w kodzie więc zamiast tego jest capslock

public class JETPACKSPOT: InventorySpot
{
    public override bool putItemIn(Item itemToPut)
    {
        if (itemToPut is JETPACK)
        {
            if (base.putItemIn(itemToPut))//call the derived function and see if it succeeded
            {
                //let player know he has a new jetpack
                GameObject.FindObjectOfType<Player>().JETPACK = (JETPACK)item;//item (Item item - derived from InventorySpot)
                return true;
            }
            else
                return false;
        }
        else
        {
            Debug.Log("item types do not match");
            return false;
        }
    }
}
komentarz 26 marca 2017 przez rafal.budzis Szeryf (85,260 p.)

Moim zdaniem 10 linijka powinna być gdzieś wyżej przy wywoływaniu funkcji lub został obsłużona przez eventy. Na pewno ciekawszym rozwiązaniem było by stworzenie eventu w klasie Item na ubranie itemu oraz wywołanie eventu w klasie InventorySpot w metodzie putItemIn. Wyedy w tym evencie wykonujesz 10 linijke. A twój kod wygląda tak 

public class JETPACKSPOT: InventorySpot
{
    public override bool putItemIn(Item itemToPut)
    {
        if (itemToPut is JETPACK)
        {
             return base.putItemIn(itemToPut;
        }

        Debug.Log("item types do not match");
        return false;
    }
}

Warto pamiętać ze return przerywa działanie funkcji i drugi return nie musi być w else ;)

1 odpowiedź

+1 głos
odpowiedź 26 marca 2017 przez obl Maniak (51,280 p.)
wybrane 26 marca 2017 przez Adam Olesiak
 
Najlepsza
Każda z klas, która może zastać wrzucona do plecaka powinna dziedziczyć ten sam interfejs. Wtedy będziesz sprawdzał, czy klasa dziedziczy po takim a takim interfejsie i jeżeli tak to może zostać wrzucona do plecaka. Innymi słowy poczytaj o interfejsach.

W C# można dziedziczyć tylko po jednej klasie i po dowolnej liczbie interfejsów.
komentarz 26 marca 2017 przez Adam Olesiak Gaduła (3,290 p.)

Dzięki za odpowiedź!

 

Przy okazji jak mogę jeszcze zapytać:

Jak w C# przechowywać coś(np wskaźnik) do typu?

Chodzi mi o coś takiego(tylko działającego):

class A
{
    Type someOtherClassB;
}

 

1
komentarz 26 marca 2017 przez NowyUrzydgownig Mądrala (5,090 p.)
Jeżeli masz klasę A i po tej klasie dziedziczą klasy B,C,D .... . To te klasy B,C,D możesz przechowywać np. w liście typu A. Rzutujesz w ten sposób w górę. Jak chcesz wydobyć klasę B, to musisz rzutować w dół. Czyli sprawdzasz, czy to jest ta klasa B poprzez is B i jak jest to tworzysz referencję typu B i przypisujesz do niej zrzutowaną w dół klasę A. Rzutujesz w dół tak: A as B.
komentarz 26 marca 2017 przez NowyUrzydgownig Mądrala (5,090 p.)
Jeżeli te klasy B,C,D nie dziedziczą po A, albo np. klasa B dziedziczy po A, lecz C,D już nie dziedziczy, to zaimplementuj w każdej klasie interfejs i zrób listę o typie tego interfejsu.
komentarz 26 marca 2017 przez Adam Olesiak Gaduła (3,290 p.)

Nie do końca rozumiem o co chodzi z interfacami, ale jak dobrze rozumiem to chodzi Ci o coś takiego, nie?

public class JetpackSpot : InventorySpot
{
    Item acceptableItemType = new Jetpack();

    public override bool putItemIn(Item itemToPut)
    {
        if (Object.ReferenceEquals(itemToPut.GetType(), acceptableItemType.GetType()))
            return base.putItemIn(itemToPut);
        else
            return false;
    }
}

testowałem i działa - to już jest dosyć "eleganckie" rozwiązanie? ;)

komentarz 26 marca 2017 przez NowyUrzydgownig Mądrala (5,090 p.)
Taka zasada jest, że jak piszesz interfejs to poprzedzasz jego nazwę dużym I, aby było wiadomo że to interfejs. Popatrz sobie na interfejsy w .NET wszystkie zaczynają się na I.
komentarz 26 marca 2017 przez obl Maniak (51,280 p.)

Obczaj to:

    interface Ipoint2d
    {
        int X { get; set; }
        int Y { get; set; }
    }

    class Point2d : @interface.Ipoint2d
    {
        protected int x;

        public int X
        {
            get { return x; }
            set { x = value; }
        }
        protected int y;

        public int Y
        {
            get { return y; }
            set { y = value; }
        }

        public Point2d(int x, int y)
        {
            this.x = x;
            this.y = y;
        }

        public override string ToString() // przeładowana metoda ToString klasy bazowej Object
        {
            return "Point2D x = " + x + "; y = " + y;
        }
    }

    class Human : Point2d{
        private string humanName;
        public Human(int x, int y, string humanName) : base(x, y){
            this.humanName = humanName;
        }
    }

    class Dron : Point2d{
        private string dronName;
        public Dron(int x, int y, string dronName) : base(x, y){
            this.dronName = dronName;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var mylist = new List<Ipoint2d>();
            mylist.Add(new Human(0, 0, "Lord Władek"));
            mylist.Add(new Dron(10, 5, "R2PI2"));

            foreach (Ipoint2d obj in mylist)
            {
                Console.WriteLine(obj.ToString());
                Console.WriteLine(obj.GetType());
            }

            Console.ReadKey();
        }
    }

Poza tym obiekty różnych typów możesz przechowywać w jednej liście, pod warunkiem, że ta lista będzie przyjmowała elementy typu Object wtedy to będziesz mógł tam wrzucić dosłownie wszystko, bo każdy  typ w C# (o ile dobrze pamiętam) dziedziczy po Object.

Podobne pytania

0 głosów
2 odpowiedzi 591 wizyt
pytanie zadane 14 grudnia 2016 w C# przez Alex.Ironside Stary wyjadacz (14,880 p.)
0 głosów
3 odpowiedzi 800 wizyt
pytanie zadane 11 maja 2017 w OpenGL, Unity przez dzidziamocarz Początkujący (370 p.)
0 głosów
1 odpowiedź 334 wizyt
pytanie zadane 2 września 2019 w C# przez XavRock Obywatel (1,390 p.)

92,453 zapytań

141,262 odpowiedzi

319,088 komentarzy

61,854 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Akademia Sekuraka 2024 zapewnia dostęp do minimum 15 szkoleń online z bezpieczeństwa IT oraz dostęp także do materiałów z edycji Sekurak Academy z roku 2023!

Przy zakupie możecie skorzystać z kodu: pasja-akademia - użyjcie go w koszyku, a uzyskacie rabat -30% na bilety w wersji "Standard"! Więcej informacji na temat akademii 2024 znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...