Skip to content

Instantly share code, notes, and snippets.

@pjastr
Last active November 2, 2017 22:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pjastr/9ececa8b0455be6ce8edf2d3c723e752 to your computer and use it in GitHub Desktop.
Save pjastr/9ececa8b0455be6ce8edf2d3c723e752 to your computer and use it in GitHub Desktop.

Interfejs IComparable służy do porządkowania (sortowania) obiektów. W odróżnieniu od interfejsu IComparable<T> nie jest to tym generyczny, więc teoretycznie możliwe jest sortowanie obiektów niezależnych/różnych typów. Podpięcie do klasy wymaga implementacji metody CompareTo, ale parametr tej metody jest obiektem systemowej klasy Object. Do właściwego działania zazwyczaj musimy zrzutować obiekt na jakiś typ. Warto pamiętać, że porównywanie obiektów różnych typów jest konkstrukcją "dosyć ryzykowną", może powodować wyjątki, po trochę też łamie to filar abstrakcji (lepiej warto wyodrębnić abstrakcję np. przez dziedziczenie).

Implementacja metody CompareTo(Object) musi zwracać liczbę typu int wg następujących właściwości:

  • Mniej niż zero - Obiekt bieżący < other
  • Zero - Obiekt bieżący = other
  • Większa niż zero - other < obiekt bieżący

Przykładowa klasa Temperatura, gdzie sortowanie jest od najmniejszej wartości do największej:

    class Temperatura : IComparable
    {
        private double wartosc;

        public Temperatura(double wart) //konstruktor
        {
            this.wartosc = wart;
        }

        public int CompareTo(Object obj)
        {
            if (obj == null) return 1;

            Temperatura other = obj as Temperatura;  //traktowanie obj jako typ Temperatura
            if (other != null)
            {
                if (other.wartosc < this.wartosc)
                {
                    return 1;
                }
                else if (other.wartosc == this.wartosc)
                {
                    return 0;
                }
                else
                {
                    return -1;
                }
            }
            else
                throw new ArgumentException("Objekt nie jest temperaturą"); //wyrzucenie wyjątku
        }

        public override string ToString()  //przesłonięcie metody (aby można było wypisać na konsoli)
        {

            return this.wartosc.ToString();
        }
    }

Pełny kod: https://github.com/pjastr/Ex503

Uwaga: sprawdzanie nulla i wyrzucanie wyjątku nie zawsze jest potrzebne do kompilacji. To raczej dobrego "opiekowania się kodem".

Możemy również skorzystać z faktu, że systemowe typy (np. liczbowe, stringi, czary) mają już zaimplementowany ten interfejs. Wtedy możemy użyć nieco innej składni. Poniżej przykładowa klasa Pracownik (sortowanie jest od najwyższego wynagrodzenia, potem wg imienia od A do Z).

    class Pracownik : IComparable
    {
        private int wynagrodzenie;
        private string imie;

        public int CompareTo(Object obj)
        {
            Pracownik other = obj as Pracownik;  //traktowanie obj jak pracownika
            if (this.wynagrodzenie == other.wynagrodzenie)
            {
                return this.imie.CompareTo(other.imie);
            }
            return other.wynagrodzenie.CompareTo(this.wynagrodzenie);
        }

        public Pracownik(string imie, int wynagrodzenie) //konstruktor
        {
            this.imie = imie;
            this.wynagrodzenie = wynagrodzenie;
        }

        public override string ToString() //przesłonięcie metody
        {
            return this.imie + " " + this.wynagrodzenie;
        }

    }

Pełny kod: https://github.com/pjastr/Ex504

Trzecia sytuacja: w metodzie CompareTo chcemy porównywać obiekty z dwóch typów. W przykładzie mamy klasy Ptak i Ssak. Mechnizm sortowania jest następująco: - najpierw ssaki alfabetycznie, potem ptaki - odwrotnie alfabetycznie.

    class Ssak:IComparable
    {
        private string nazwa;

        public Ssak(string nazwa)
        {
            this.nazwa = nazwa;
        }

        public int CompareTo(object obj)
        {
            if (obj is Ssak)
            {
                return this.nazwa.CompareTo((obj as Ssak).nazwa);
            }
            else if (obj is Ptak)
            {
                return -1;
            }
            else
            {
                throw new ArgumentException("Objekt nie jest ptakiem ani ssakiem.");
            }
        }

        public override string ToString()
        {
            return this.nazwa;
        }
    }
    class Ptak:IComparable
    {
        private string nazwa;

        public Ptak(string nazwa)
        {
            this.nazwa = nazwa;
        }

        public int CompareTo(object obj)
        {
            if (obj is Ptak)
            {
                return (obj as Ptak).nazwa.CompareTo(this.nazwa);
            }
            else if (obj is Ssak)
            {
                return 1;
            }
            else
            {
                throw new ArgumentException("Objekt nie jest ptakiem ani ssakiem.");
            }
        }

        public override string ToString()
        {
            return this.nazwa;
        }
    }

Pełny kod: https://github.com/pjastr/Ex505

Takie rozwiązanie też nie jest najlepsze. Trzeba ostrożnie dodać właściwą implementację w obu klasach.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment