Błąd Listy obiektów

0

Witam, chciałbym przestawić tutaj swój problem mianowicie :

  1. mam oto taki (wycinek) kodu odpowiedzialnego za pobieranie listy folderów
class Dane
.....
private List<Dokument> Lista = new List<Dokument>();

public List<Dokument> PobierzPlikiIFoldery(string sciezka)
        {
            Lista.Clear();
            string[] foldery = Directory.GetDirectories(sciezka);
            foreach (string s in foldery)
            {
                Dokument dokument = new Dokument(s,Typ.katalog);
                Lista.Add(dokument);
            }

            string[] pliki = Directory.GetFiles(sciezka);
            foreach (string s in pliki)
            {
                Dokument dokument = new Dokument(s, Typ.plik);
                Lista.Add(dokument);
            }

            return Lista;
        }
...

tutaj kod klasy Dokument :

class Dokument
{
        private string _nazwa;
        private long _rozmiar;
        private DateTime _dataUtworzenia;
        private Typ _typ;

        public string sciezka;      
        public string sciezka_do;
......
}

W pliku głównym mam zadeklarowane 2 listy (program ma być coś ala norton comander), lista lewa to pliki i foldery z np. C:, a lista prawa to samo tylko z np D:

        Dane dane = new Dane();
        List<Dokument> DrzewoLewe = new List<Dokument>();
        List<Dokument> DrzewoPrawe = new List<Dokument>();

Mam również funkcję odpowiedzialną za Używanie i dodawanie elementów do ListView :

private void PobierzPlikiiFoldery(ref List<Dokument> Drzewo,ref ListView listView,string sciezka)
        {
            try
            {
                Drzewo = dane.PobierzPlikiIFoldery(sciezka);
                listView.Items.Clear();
                for (int i = 0; i < Drzewo.Count; i++)
                {
                    ListViewItem item = new ListViewItem(Drzewo[i].Nazwa);

                    Konwersja k = new Konwersja(Drzewo[i].Rozmiar);

                    if (Drzewo[i].typ == Typ.katalog)
                        item.SubItems.Add("katalog");
                    else
                        item.SubItems.Add(k.Podziel());

                    item.SubItems.Add(Drzewo[i].DataUtworzenia.ToString());
                    listView.Items.Add(item);

                    if (Drzewo[i].typ == Typ.plik) listView.Items[i].ForeColor = Color.SteelBlue;
                }
            }
            catch
            {
                label3.Text = "BŁĄD : pobrania drzewa";
            }
        }

Powiedzmy, że probranie listy katalogów i plików odbywa się w taki posób

dla woli jasności :: TextBox1.Text = "C:"
i w drógim przypadku TextBox2.Text = "D:"

funkcji używam w taki posób dla 1 lub 2 buttonu

PobierzPlikiiFoldery(ref DrzewoLewe, ref listView1, textBox1.Text);

PobierzPlikiiFoldery(ref DrzewoPrawe, ref listView2, textBox2.Text);

Błąd polega na tym, że jeśli pobiorę np 1 sposobem to DrzewoLewe ma listę plików taką jaką ma mieć a Drzewo Prawe jest puste, czyli wszysto ok.

Jeśli zaś Drzewo Lewe ma jakieś dane i kliknę pobierz Drzewo Prawę, to wartośći z Drzewa Lewego = Drzewa Prawego, i działa to także w drugą strone, dane się po prostu nadpisują.

Myślę ze błąd popełniłem gdzieś przy referencjach, niestety nie mogę dojsć gdzie :/

0

masz racje, zakreciles sie przy referencjach, ale nie przy REF a duuuzo wczesniej i to przy 'natywnych referencjach', czyli po prostu zle przesledziles ktora zmienna pokazuje na jaki obiekt..

zerknij tu, kod dobrze znasz, nic nie zmienione, tylko oznaczone :

class Dane
.....
private List<Dokument> Lista = new List<Dokument>();   // obiekt typu Dane ma 1 liste

public List<Dokument> PobierzPlikiIFoldery(string sciezka)
        {
            Lista.Clear();     // obiekt typu Dane czysci sobie ta liste
            string[] foldery = Directory.GetDirectories(sciezka);
            foreach (string s in foldery)
            {
                Dokument dokument = new Dokument(s,Typ.katalog);
                Lista.Add(dokument);
            }

            string[] pliki = Directory.GetFiles(sciezka);
            foreach (string s in pliki)
            {
                Dokument dokument = new Dokument(s, Typ.plik);
                Lista.Add(dokument);
            }

            return Lista;   // i pozniej tę listę zwraca, zawsze tę samą, zeby 'oszczedzic' na obiektach
        }

tworzysz sobie pozniej obiekty robocze:

Dane dane = new Dane();  // jeden obiekt do sciagania list dokumentow
List<Dokument> DrzewoLewe = new List<Dokument>();  // 'robocze'
List<Dokument> DrzewoPrawe = new List<Dokument>();   // 'robocze'

i pozniej, uzywasz ich tak:

    private void PobierzPlikiiFoldery(ref List<Dokument> Drzewo,ref ListView listView, string sciezka)  
    // zwroc uwage na parametry: jest lista robocza, kontrolka docelowa, ale nie ma obiektu typu Dane
        {
            try
            {
                Drzewo = dane.PobierzPlikiIFoldery(sciezka);  // obietu typu dane uzywasz!
                // skad jest ten obiekt? pewnie gdzies na zewnatrz go masz i jest to zawsze
                // ten sam obiekt
                // ale jak go uzywasz? dostajesz od niego LISTE i zapamietujesz ja w DRZEWO
                // to znaczy, ze wlasnie 'zapomniales' o obiekcie roboczym, a na jego miejsce
                // wiążesz zmienna 'Drzewo' z ... wynikiem metody, czyli listę którą obiekt
                // typu Dane (zawsze ten sam) pamięta, czysci, wypelnia i pozniej tę zwraca
                // (zawsze tę samą, zeby 'oszczedzic' na obiektach)

                listView.Items.Clear();
                for (int i = 0; i < Drzewo.Count; i++)
                {
                    blahblahblahblah
                    reszta kodu nie wazna

niby na razie wszystko gra, ale teraz spojrz:

PobierzPlikiiFoldery(ref DrzewoLewe, ref listView1, textBox1.Text);
PobierzPlikiiFoldery(ref DrzewoPrawe, ref listView2, textBox2.Text);

po takiej sekwencji, DrzewoLewe i DrzewoPrawe beda pokazywac na... TEN SAM obiekt, na te-liste-co-zawsze, pamietana przez Dane! kazde wywolanie PobierzPlikiiFoldery(ref X,..) bedzie powodowalo, ze zmienna X bedzie sie ustawic na ten obiekt, ktory 'Dane' sobie pamietaja.

tyle tutułem diagnozy.
Rozwiązanie:

  • albo obiekt typu Dane nie powinien cacheowac listy, tylko za kazdym razem robic nowa. btw. po co cacheowac? nie widze zebys korzystal z cachingu. za kazdym razem i tak od nowa ja czyscisz, nawet jak sciezka ta sama. listy sa lekkie, new List() nie boli, bolec co najwyzej moze pamietanie jakiejs horrendalnie duzej zawartosci. jesli metoda zwracac bedzie za kazdym razem nowy obiekt listy, przestaja miec sens linijki:
List<Dokument> DrzewoLewe = new List<Dokument>();  // 'robocze'
List<Dokument> DrzewoPrawe = new List<Dokument>();   // 'robocze'

gdyz te dwa 'robocze' obiekty zostana zgubione juz po pierwszym wstepnym ladowaniu danych poprzez dane.PobierzPlikiIFoldery

  • albo, NIE NADPISUJ zmiennej Drzewo nowa referencja do obiektu, tylko PRZEPISZ otrzymane dane do niej. w ten sposob robocze listy faktycznie beda uzywane, beda odrebne, a lista-ta-co-zawsze z obiektu typu Dane bedzie faktycznie tylko tymczasowa trzymajka na wyniki. W takim przypadku nie potrzebujesz 'ref' przy pierwszym parametrze metody. zmienna sie nie zmienia, pokazuje na ten sam obiekt caly czas.

btw. z tego samego podowu NIE potrzebujesz 'ref' przy drugim parametrze. obiekt kontrolki sie nie zmienia na inny, prawda? patrzac po zatłoczeniu tych 'ref' mam lekkie wrazenie ze merdnęło Ci się z "Type & varnme" z C++. pamietaj ze tutaj kazdy obiekt poza tymi 'struct' jest zawsze przekazywany przez referencje. Pobranie parametru 'ListView listView' zamiast 'ref ListView listView' nie spowoduje lokalnego skopiowania kontrolki! Twoj ostatni parametr tez jest przekazywny przez referencje, gdyz string to Class nie Struct - tylko tego nigdy nie dostrzezesz, gdyz po prostu nie masz jak zmodyfikowac tego obiektu stringa (no, poza gimnastyką ze StringBuilderem)

0

Dziękuję bardzo za odpowiedź. Szukałem błędu a niestety nie pomyślałem jak to program analizuje i że faktycznie przydałby się nowy obiekt dane / nowa lista ;)

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