lista -> csv

0

Witam, potrzebuję by listę obiektów zapisać do pliku csv.

                public void writeStream<T>(List<T> list)
                {
                 string s = String.Join(";", list.Select(x => x.ToString()).ToArray());
                 File.WriteAllText("data.csv", csv);
                }
            

Zrobiłem coś takiego i działa, w zasadzie o to mi chodizło. Zastanowiłem się jednak, w jaki sposób zrobić to w ten sposób by każde property było oddzielone ";" (a nie sam "kompletny" obiekt) a każdy właśnie "pełny" obiekt znajdował się w nowej linii. Macie jakiś pomysł? :)

1

zrob interfejs ktore zawiera property te ktore chcesz odzielic i jako type w genericu daj te interfejsy. Klasy ktore przekazuja beda musialy dziedziczyc po tych interfejsach.

w petli wtedy bedziesz mogl sie odwolywac do wlasciwosci i robic z nimi co chcesz

0

Dzięki, rzeczywiście wtedy mam dostęp do property , które potrzebuję :) ale problem mam taki, że jak zmienię typ T na Interface1 to w mainie nie mogę wrzuciś sobie listy typu powiedzmy Reader na przykład.

0

Mówiąc ściślej, bo napisałem niejasno - w metodzie jak argument podaję listę dowolnego typu. Jeśli wrzucę tam interfejs jako type to mam dostęp do property w metodzie ale nie wywołam tej metody dla dowolnego typu listy, tylko dla listy typu interfejsu.

1

Możesz.

public void writeStream<T>(List<T> list)
where T: MyMagicInterface
{
}
0

Bajecznie, dzięki Ci wielkie. Pozdrawiam.

1

jak chcesz zeby ci dzialalo dla dowolnego typu to musisz dostarczyc jakis konwerter, niby skad program ma wiedziec co ma wrzucic do csv z dowolnego typu? :)
jak nie chcesz sie bawic w interfejsy/klasy opakowujace wlasciwy typ to mozesz podawac do metody funkcje konwertujaca, np cos takiego:

public static void WriteCsv<T>(IEnumerable<T> data, Func<T, IEnumerable<string>> propertiesProvider)
        {
            var csv = data.Select(item => string.Join(";", propertiesProvider(item)));
            File.WriteAllLines("data.csv", csv);
        }
0

Jesteście wielcy :) Udało mi się to wszystko zrobić tak jakbym chciał. Pomyślałem też o deserializacji. Załóżmy , że chciałbym te dane z pliku CSV zapisać do mojej listy.

  public void readStream<T>(List<T> list) where T : Interfaces.Interface1
        {
            FileStream file = new FileStream("data.csv", FileMode.Open);
            StreamReader reader = new StreamReader(file);
            string line;
            while ((line = reader.ReadLine()) != null)
            {
                String[] data = line.Split(';');
                String prop1 = data[0];
                String prop2 = data[1];
                String prop3 = data[2];
                // ???? :( 
            }

        }
 

Przyjmijmy może trochę naiwne założenie, że property obiektu mogą być 3. Macie pomysł jak dalej "pociągnąć te dane do mojej listy (List<T> list)?

1

Jeśli Interface1 ma publiczne setery, a T publiczny bezparametrowy konstruktor, to można np. tak:

public List<T> ReadCsv<T>(string fileName) 
where T : Interfaces.Interface1, new()
{
    List<T> list = new List<T>();
    using(FileStream file = new FileStream(fileName, FileMode.Open))
    using(StreamReader reader = new StreamReader(file))
    {
        string line;
        while ((line = reader.ReadLine()) != null)
        {
            String[] data = line.Split(';');

            var item = new T();
            item.Prop1 = data[0]
            item.Prop2 = data[1];
            item.Prop3 = data[2];      
        
            list.Add(item);
        }
    }

    return list;
}

Jeśli nie ma publicznych seterów, za to konstruktor, to np. tak:

public List<T> ReadCsv<T>(string fileName) 
where T : Interfaces.Interface1, new()
{
    List<T> list = new List<T>();
    using(FileStream file = new FileStream(fileName, FileMode.Open))
    using(StreamReader reader = new StreamReader(file))
    {
        string line;
        while ((line = reader.ReadLine()) != null)
        {
            String[] data = line.Split(';');
            var item = Activator.CreateInstance(typeof(T), data); 
            list.Add(item);
        }
    }

    return list;
}
0

Dzięki twojej pomocy osiągnąłem zamierzony efekt ;) Byłbym Ci jeszcze bardziej wdzięczny jeśli mógłbyś mi tylko jeszcze wyjaśnić poniższą konstrukcję:

 public void readStream<T>(List<T> list) where T : Interfaces.Interface1, new() 

Rozumiem , że definiuję publiczną metodę (generic) typu void , która przyjmuję jako parametr pewną kolekcję (tutaj listę). Jednak chciałbym żebyś tutaj wyjaśnił mi ten fragment:

 where T : Interfaces.Interface1, new()

Czy chodzi o to, że po prostu T musi być typu referencyjnego, mówiąc ściślej - typ , który umieścimy po słowie kluczowym where? No i nie bardzo wiem, co oznacza to new(). Z góry dziękuję Ci / Wam za odpowiedź :)

1

where w tym przypadku służy do nałożenia ograniczeń na typ T. Dzięki temu mamy pewność, że metoda zadziała tylko z typami dziedziczącymi z Interface1. A new() oznacza, że typ T musi mieć publiczny, bezparametrowy konstruktor.

https://msdn.microsoft.com/en-us/library/bb384067.aspx

0

Ehh, może jednak nie będę spamił nowym tematem, mam jeden problem natury technicznej:

 String[] data = line.Split(';');
                     var item = new T();
                    int[] values = new int[data.Length];
                    item.id = values[0];
                    item.name = data[1];
                    item.lastname = data[2]; 

Przy wypisaniu całej listy w 1 kolumnie mam same zera, chociaż w pliku, z którego deserializuje są inne dane. W jaki sposób mogę przekonwertować taką wartość?

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