Zaleta niestatycznego typowania

Do oprogramowania miałem 4 combo boxy zgodnie z zasadą, że po wybraniu czegoś w pierszym odświeża się drugi (modelami, które są właściwe dla marki wybranej w pierwszym combo). Analogicznie następne combo boxy.

Wyglądało mi to na strukturę drzewiastą. Na początku myślałem, że powinien to być słownik w słowniku w słowniku a na końcu wystarczy już lista.

private Dictionary<string, Dictionary<string, Dictionary<string, List<string>>>> _dictionary; 

Problem

Nigdy nie deklarowałem dłuższego typu, wiedziałem, że coś robię źle. Nie było to czytelne i zrozumiałe na pierwszy i drugi rzut oka. Jakakolwiek zmiana (dodanie combo) byłaby pewnie bolesna. Później przyszedł czas na implementację, najpierw wypełniania słownika (z drzewa folderów), później wypełniania combo boxów. Skoro zasada działania combo boxów jest podobna, to dobrze byłoby mieć funkcję rekurencyjną. Niestety jedna nie wystarczała, ponieważ List trzeba inaczej obsłużyć niż Dictionary.

Poszedłem na spacer i wymyśliłem, że zadeklaruję po prostu:

private Dictionary<string, object> _dictionary;

Wątpliwości

W tym momencie wypada przypomnieć temat tego posta. C# jest statycznie typowany, więc należy korzystać z tej cechy (zalety) języka. Kiedyś usłyszałem, że początkującym programistą powinno się zakazywać rzutowania, ponieważ uczy to złych nawyków. Wziąłem to sobie do serca, zwłaszcza że wiedziałem już jak pisać kod, który nie wymaga rzutowania i stosowania operatorów is oraz as dla sterowania logiki programu.

Użycie luźnego typowania i rzutowania

Zrobiłem więc, uprawniony według mnie wyjątek i wyszło całkiem dobrze. Mimo że na końcu tego drzewa sa obiekty Dictionary robiące za słupy (tylko dlatego, że słownik wyżej musi na coś wskazywać). Nie przejmuję się też ile poziomów ma drzewo.

Fukcja budująca drzewo:

        private void FillRecursive(int level, string folder, Dictionary<string, object> dict)
        {
            // warunek przerwania rekurencji
            if (level <= 0)
                return;

            foreach (var innerFolder in Directory.EnumerateDirectories(folder))
            {
                var innerDict = new Dictionary<string, object>();

                // innerDict dodany dodany do dict jako typ object
                dict.Add(new DirectoryInfo(innerFolder).Name, innerDict);

                FillRecursive(level - 1, innerFolder, innerDict);
            }
        }

Funkcja wypełniająca drzewo jest trochę bardziej zagmatwana, więc jej nie wrzucę. Jest w niej oczywiście kawałek zawierający tytułowe rzutowanie, którego jak opisałem staram się unikać w większości przypadków:

dict = (Dictionary<string, object>)dict[GetText(combo)];
Reklamy
Ten wpis został opublikowany w kategorii Programowanie i oznaczony tagami , . Dodaj zakładkę do bezpośredniego odnośnika.

6 odpowiedzi na „Zaleta niestatycznego typowania

  1. Arkadiusz Bal pisze:

    Rozpędziłeś się za bardzo moim zdaniem 🙂

    Skoro i tak musisz wiedzieć co dane foldery zawierają by odpowiednie Combo wyświetlać to rzeczywiście ztypuj to jak należy na twardo do takiej hierarchii:

    class Root
    List CarCompanies
    CarCompany Curr

    class CarCompany
    List CarModels
    CarModel Curr

    class CarModel
    List CarModelTypes
    CarModelType Curr

    class CarModelType
    List Numbers
    string Curr

    Wtedy masz:

    Root root
    root.Curr.Curr.CarModelTypes typy dla wybranego modelu
    root.Curr.Curr.Curr.Curr voila wybrany numer

    • Dzięki, już się temu przyglądam. Myślałem na początku, że tworzenie osobnej klasy na każdym stopniu hierarchii będzie w tym wypadku „tworzeniem bytów bez potrzeby”. Przemyślę i pewnie wybiorę Twoje rozwiązanie.

  2. olgatherer pisze:

    Wydaje mi się, że tu aż się prosi o zastąpienie tego słownika odpowiednią klasą…
    A już gdy widzę proponowane rozwiązanie, to jestem przekonany, że wszystko lepsze niż ono.

  3. olgatherer pisze:

    Arek pisze:
    Root root
    root.Curr.Curr.CarModelTypes typy dla wybranego modelu
    root.Curr.Curr.Curr.Curr voila wybrany numer

    Kiedy widzę tyle kropek, od razu włącza mi się światełko: potencjalne pogwałcenie prawa Demeter – należałoby to przemyśleć.
    W zależności od konkretnego problemu dodatkowo można choćby skorzystać z czegoś na kształt kompozytu, aby uprościć kod. W każdym razie nie dla słownika oraz nie dla wielu kropek w wywołaniach 🙂

  4. Andrzej Błaszczuk pisze:

    Proponuję tak
    1. Klasa Samochod, z propertisami: Marka, Model, Typ, Rejestracja
    2. Klasa KolekcjaSamochodow (Samochody mało różni się od Samochod, więc dodałem kolekcja ale z myślą zbiór – grupa) z prywatnym kontenerem (np. listą, ale może być cokolwiek) obiektów Samochod
    Klasa KolekcjaSamochodow miałaby metody typu PobierzWszystkieModeleDlaMarki itp.

    Implementacja tych metod to blisko jedna linia w linqu na kolekcji.
    var ModeleDlaMarki = from samochod in kolekcjaSamochodow
    where samochod.Marka == zadanaMarka
    select samochod.Model;

    Zmiany w strukturze danych (nowe pola) oraz w ich relacjach – logice biznesowej byłyby łatwe w utrzymaniu.

    Uwagi na marginesie:
    W tym wpisie zmienne są nazywane tak, jak się nazywają elementy języka a nie dziedziny aplikacji. Nazwa _dictionary oraz FillRecursive mówią JAK to jest zrobione, ale nie mówią CO.
    Dla pierwszej proponowałbym coś jak _cars a dla metody coś jak ReadCarsFromFolder.

Możliwość komentowania jest wyłączona.