W jaki sposób użyć metody klasy do której zwracamy interface?

0

Witam, mam interface który pomaga mi przy zapisie i odczycie dzięki funkcjom która zamienia obiekt do lini CSV, oraz funkcji która zamienia linię CSV na obiekt.

Funkcja która zapisuje wygląda tak:

        public static void SaveToFile(this List<ISaveable> data, string filename)
        {
            List<string> lines = new List<string>();
            string path = Path.Combine(AppConfig.AppDataFolder, filename);


            foreach (ISaveable item in data)
            {
                lines.Add(item.ToCSV());
            }

            File.WriteAllLines(path, lines);
        }

Teraz chciałbym zrobić funkcję która z pliku czyta:

        public static List<ISaveable> ReadFromFile(this string filename)
        {
            List<ISaveable> result = new List<ISaveable>();
            string path = Path.Combine(AppConfig.AppDataFolder, filename);

            if (!File.Exists(path))
            {
                return result;
            }
            List<string> input = File.ReadAllLines(path).ToList();
            foreach (var item in input)
            {
                result.Add((Klasa do ktorej chce zapisac).FromCSV(item));
            }

            return result;

problem jest taki, że muszę wiedzieć w funkcji do jakiej konkretnie klasy chcę zapisać i nie wiem jak to zrobić.

Jedna z opcji o ktorych mysle to przekazanie obiektu klasy do ktorej chce zapisac:

public static List<ISaveable> ReadFromFile(this string filename, ISaveable saveTo)
        {
            List<ISaveable> result = new List<ISaveable>();
            string path = Path.Combine(AppConfig.AppDataFolder, filename);

            if (!File.Exists(path))
            {
                return result;
            }
            List<string> input = File.ReadAllLines(path).ToList();
            foreach (var item in input)
            {
                result.Add(saveTo.FromCSV(item));
            }

            return result;
        }

Jednak nie lubię tego rozwiązania. Istnieje jakiś inny sposób? Szukałem w google w jaki sposób funkcja może użyć metod klasy do której przekazuje return ale nic nie znalazłem.

0

Co to jest FromCSV? Metoda interfejsu ISaveable?
Wydaje mi się że próbujesz rozwiązać nieistniejący problem.

0
Azarien napisał(a):

Co to jest FromCSV? Metoda interfejsu ISaveable?
Wydaje mi się że próbujesz rozwiązać nieistniejący problem.

Tak, FromCSV to metoda interfejsu ISeavable która zamieni string na obiekt danej klasy.

0

Udało mi się problem rozwiązać:

public static List<ISaveable> ReadFromFile(this ISaveable saveto, string filename)
        {
            List<ISaveable> result = new List<ISaveable>();
            string path = Path.Combine(AppConfig.AppDataFolder, filename);

            if (!File.Exists(path))
            {
                return result;
            }
            List<string> input = File.ReadAllLines(path).ToList();
            foreach (var item in input)
            {
                result.Add(saveto.FromCSV(item));
            }

            return result;
        }

Używam:

            List<ISaveable> list = new List<ISaveable>();
            list = new Customer().ReadFromFile("Customers.dat");

Dalej nie podoba mi się to, że muszę tworzyć obiekt używający interfejsu ISaveable tylko po to, żeby użyć tej metody ale nic lepszego nie udało mi się wymyślić. Każdy inny sposób jaki znalazłem powodowałby powielanie kodu w mniejszym lub większym stopniu.

0
t0m3k__ napisał(a):

Dalej nie podoba mi się to, że muszę tworzyć obiekt używający interfejsu ISaveable tylko po to, żeby użyć tej metody ale nic lepszego nie udało mi się wymyślić. Każdy inny sposób jaki znalazłem powodowałby powielanie kodu w mniejszym lub większym stopniu.

Hmm, czy dobrze rozumiem? Nie podoba Ci się, że musisz utworzyć obiekt, na rzecz którego chcesz wywołać metodę? Czegoś tu nie rozumiem. Może opowiedz dokładnie CO chcesz osiągnąć. Od samego początku. Jaki konkretnie jest problem, który spowodował, że napisałeś ten kod.

1

Wydaje mi się, że głównym problemem tutaj jest fakt, iż metoda FromCSV jest jednocześnie instancyjna i służy do utworzenia instancji, co jest po prostu bez sensu. Użyj metody statycznej albo konstruktora.
Albo napisz mechanizm generyczny, który nie wymaga żadnych interfejsów do działania, a po prostu np. mapuje kolumny z pliku CSV na właściwości obiektu i odwrotnie.

0

Napiszę co chcę zrobić.
Mam kilka klas które przechowują dane, dane są przechowywane w List<MojaKlasa>. Chcę żeby każda z tych klas była w łatwy sposób zapisywalna i odczytywalna do i z pliku.
Stworzyłem więc Interface ISaveable który wymaga metod ToCSV() oraz FromCSV(). ToCSV() zamieni obiekt klasy na string, FromCSV() zamieni string na obiekt klasy.
Następnie utworzyłem metodę static SaveToFile(this List<ISaveable> data, string filename) która zapisze List<ISaveable> do pliku oraz metodę static ReadFromFile(this ISaveable saveto, string filename) która powinna zwrócić List<ISaveable> z pliku.
Dzięki temu nie muszę pisać oddzielnych metod do zapisywania i odczytywania różnych klas, jedynie każda klasa musi posiadać funkcję FromCSV() oraz ToCSV().

Nie wiem jak to inaczej zrobić logicznie, mechanizm generyczny nie pozwoli mi na korzystanie z metod klasy.

Jakiś inny sposób na masowy zapis klas bez powtarzania tego samego kodu?
Znalazłem to:
http://blog.danskingdom.com/saving-and-loading-a-c-objects-data-to-an-xml-json-or-binary-file/
Jednak dzieje się tam magia której nie rozumiem (rozumiem kod, jednak nie wiem jak co robi pod maská binaryFormatter.Serialize(stream, objectToWrite); , chciałbym sam rozbić klasę na zapisywalne dane a następnie te dane samemu zamienić z powrotem na klasę.

0

No właśnie o to chodzi z mechanizmem generycznym, żebyś nie korzystał z metod klasy. Po prostu mógłby odczytywać z pliku wartości z kolumny "Imie" i umieścić ją we właściwości obiekt.Imie, podobnie z kolumny "Wiek" umieścić w obiekt.Wiek, itd. Można tak, i gotowe biblioteki do tego są dostępne na Githubie czy Nugecie.

A jeśli nie chcesz generycznie, to sam widzisz, że nie możesz mieć metody obiekt.FromCsv(), bo w momencie odczytywania z CSV ten obiekt jeszcze nie istnieje. Ponadto, dobrze trzymać się Single Responsibility Principle i oddzielić operacje plikowe od klasy, która przechowuje dane.
Ja bym poszedł w takie rozwiązanie, żeby zamiast tworzyć MojaKlasa: ISaveable mieć czystą MojaKlasa na dane, a do tego interfejs:

interface ICsvReaderWriter<T>
{
    IList<T> ReadFromCsv(string filePath);
    void WriteToCsv(string filePath, IList<T> items);
}

A potem zaimplementował MojaKlasaReaderWriter : ICsvReaderWriter<MojaKlasa> i właściwie gotowe, tej klasy możesz potem użyć do zapisu odczytu gdziekolwiek potrzebujesz.

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