Jedna metoda, zapis różnych obiektów

0

Witam

Mam w programie kilka kolekcji generycznych, na których pracuję. Do zapisu w pliku csv danych zawartych w nich stworzyłem klasy - do każdej listy niezależna klasa posiadająca metodę do zapisu obiektów znajdujących się w liście.

I tu zacząłem się zastanawiać czy nie możba by jakoś sensownie połączyć obsługi zapisu / odczytu różnych obiektów w jednej klasie, co by znacznie zmiejszyło ilość kodu. Jednak każdy z obiektów ma różną ilość właściwości i różne nazewnictwo, więc np w pętli przy zapisie nie mogę ustandaryzować formatu ciągu jaki znajduje się w metodzie writeLine() obiektu StreamWriter. To samo przy odczycie przy rozdziale linii na poszczególne komórki (separator ";") otrzymuję tablicę stringów o różnej ilości elementów.

Ma ktoś jakiś sensowny pomysł jak połączyć obsługę zapisu / odczytu różnych obiektów w jednej metodzie ?

1

poczytaj o serializacji i deserializacji.

2

Jak bawisz się csvkami, to może jakiś gotowiec do tego np.: http://joshclose.github.io/CsvHelper/

0

Właśnie! Użyj gotowca. Po co wyważać otwarte drzwi.

Jeżeli jednak bardzo chcesz to napisz interfejs:

public interface ICanBeLine
{
   string BeALine();
}

Zaimplementuj ten interfejs w tych klasach, a cała reszta kodu będzie mogła być wspólna.

Zamiast pisać interfejs możesz jednak użyć przeładowania metody ToString()

0

Takie rozwiązanie zaimplementowałem.

        public void SaveData<T>(List<T> lista, string filename) where T : IConvertData
        {
            base.SaveFile(filename);

            string path = Directory.GetCurrentDirectory().ToString() + "\\Data\\" + filename;

            using (StreamWriter sr = new StreamWriter(path))
            {
                foreach(T x in lista)
                {
                    sr.WriteLine(x.ConvertToString());
                }
                sr.Close();
            }
        }

        public List<T> LoadData<T>(string filename) where T : IConvertData
        {
            base.CreateFile(filename);

            List<T> lista = new List<T>();

            string path = Directory.GetCurrentDirectory().ToString() + "\\Data\\" + filename;
            var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);

            using (StreamReader sr = new StreamReader(fs, Encoding.Default))
            {
                while (!sr.EndOfStream)
                {
                    string[] tmp = sr.ReadLine().Split(';');
                    lista.Add((T)Activator.CreateInstance(typeof(T), tmp));
                }
                sr.Close();
            }

            return lista;
        }

CreateFile() oraz SaveFile() to metody odziedziczone z abstrakcyjnej klasy bazowej, ich zadanie sprowadza się tylko do utworzenia plików przy pierwszym uruchomieniu programu.

Obiekty list generycznych implementują interfejs IConvertData, dzięki czemu w metodzie SaveData mogę użyć ConvertToString() zwracającej sformatowany string składający się z wartości poszczególnych pól rozdzielonych średnikami.

Przy odczycie wykorzystuję konstruktor pobierający tablicę stringów.

Może nie jest to optymalny sposób, ale tak na szybko wymyślony i działa poprawnie.

0

Zamiast aktywatora możesz dodać metodę do interfejsu i przez nią przekazywać, a obiekty tworzyć operatorem new ( do listy restrykcji trzeba dodać new()).

1

Też jest to jakieś rozwiązanie, ale wymaga więcej kodu. Każdy obiekt musiałby mieć swoją implementację metody wypełniającą danymi pola nowego obiektu. A tu wszystko zamyka się w jednej metodzie.

0

dla prywatnego użytku do programu który zaraz prawdopodobnie porzucisz jest w porządku, ale ogólnie rozwiązanie jest brzydkie i dla przyszłego programisty rozwijającego kod nie będzie z góry jasne że musi posiadać bezparametrowy konstruktor - w przyszłości może zajść potrzeba żeby przyjmować parametr w konstruktorze jednej z klasy i wymusi brzydkie rozwiązania

0
marcin82w napisał(a):

Też jest to jakieś rozwiązanie, ale wymaga więcej kodu. Każdy obiekt musiałby mieć swoją implementację metody wypełniającą danymi pola nowego obiektu. A tu wszystko zamyka się w jednej metodzie.

Obecnie ten kod masz przecież w konstruktorze. Poza tym implementacja może być w obiekcie wstrzykiwanym lub dziedziczonym. Wygląda na to, że się nie zrozumieliśmy.

Mały Młot napisał(a):

dla prywatnego użytku do programu który zaraz prawdopodobnie porzucisz jest w porządku, ale ogólnie rozwiązanie jest brzydkie i dla przyszłego programisty rozwijającego kod nie będzie z góry jasne że musi posiadać bezparametrowy konstruktor - w przyszłości może zajść potrzeba żeby przyjmować parametr w konstruktorze jednej z klasy i wymusi brzydkie rozwiązania

Dla przyszłego programisty stanie się jasne jak usunie konstruktor i mu się projekt nie skompiluje to raz. Dwa to jeżeli programista piszący kod zachowa zasadę YAGNI, to taka sytuacja nie mogła by mieć miejsca. Wtedy każda metoda ma jakieś zastosowanie i nie może być tak, że po prostu sobie coś usuwasz. Ja mam inne pojęcie brzydkiego kodu.

0
DibbyDum napisał(a):

Jak bawisz się csvkami, to może jakiś gotowiec do tego np.: http://joshclose.github.io/CsvHelper/

Faktycznie, ten gotowiec jest idealnym rozwiązaniem do csv. Trochę na początku miałem problemy z zapisem polskich znaków (zmieniało je na bliżej nieokreślone znaki) jednak ustawienia kodowania pomogło.

1 użytkowników online, w tym zalogowanych: 0, gości: 1