2016-11-19 32 views
5

Mam mały problem, gdy chcę wykonać niektóre operacje w języku C#. Dam ci mały przykład.Stos listy ogólnej zostanie wyczyszczony po wyczyszczeniu listy wypychanej

Stack<List<HufmannLetter>> steps = new Stack<List<HufmannLetter>>(); 
List<HufmannLetter> letterList = new List<HufmannLetter>();  

while(true){ 

    letterList.Add("asd"); 
    letterList.Add("sad"); 

    steps.Push(letterList); 
    letterlist.Clear();  
} 

W tym kodzie chcę przesunąć listę odnośników do stosu niż usunąć wszystkie pozycje z listy. Po wyczyszczeniu listy pierwszy indeks mojego stosu znika, ponieważ jest przekazywany jako odniesienie. Czy się mylę? Ponieważ nie wiem, dlaczego tak się dzieje.

Używam metody "przekazuj według wartości".

Stack<List<HufmannLetter>> steps = new Stack<List<HufmannLetter>>(); 
List<HufmannLetter> letterList = new List<HufmannLetter>(); 

while(true) { 

    letterList.Add("asd"); 
    letterList.Add("sad"); 

    List<HufmannLetter> tempLetterList = new List<HufmannLetter>(letterList); 
    steps.Push(tempLetterList); 
    letterlist.Clear();  
} 

Czy to dobry sposób na rozwiązanie problemu? W ten sposób działa, ale czytelność maleje. Co mi sugerujesz?

Dzięki ...

+2

"Czy się mylę?" Tak, w kodzie, który pokazałeś, nie ma przejścia. Można to stwierdzić przez brak "ref" i "out". Sugeruję, abyś przeczytał http://jonskeet.uk/csharp/parameters.html i http://jonskeet.uk/csharp/references.html Zwróć uwagę, że przekazanie referencji według wartości nie jest tożsame z przekazywaniem referencji. –

Odpowiedz

3

Wystarczy utworzyć nową List<HufmannLetter> obiekt wewnątrz pętli i dodać, że do stosu. Ponowne użycie tego samego obiektu listy nie przyniesie żadnych korzyści związanych z wydajnością.

Stack<List<HufmannLetter>> steps = new Stack<List<HufmannLetter>>(); 

while(true) 
{ 
    List<HufmannLetter> letterList = new List<HufmannLetter>(); 

    letterList.Add("asd"); 
    letterList.Add("sad"); 

    steps.push(letterList); 
} 
+0

Tak, wiem, nie wpływa to na moją wydajność, ale zastanawiam się nad zrozumieniem mojego kodu. Ale jeśli nie ma żadnego sposobu, nie zmienię mojego kodu. Wielkie dzięki :) – Berkin

+1

Żadna z odpowiedzi nie wyjaśnia OP "Kiedy wyczyściłem listę, pierwszy indeks mojego stosu znika, ponieważ przeszedł przez referencję. Czy się mylę? Ponieważ nie wiem, dlaczego tak się dzieje "! –

+0

@ Berkin, co masz na myśli przez _ "nie ma mowy"? Mój przykład nie jest identyczny z twoim. –

1

Można tworzyć new List<HufmannLetter>() i dać w konstruktorze poprzedniej listy, to stworzy nowy obiekt, który nie zostanie usunięty.

while(condition) 
{ 
    letterList.Add("asd"); 
    letterList.Add("sad"); 

    steps.push(new List<HufmannLetter>(letterList)); 
    letterlist.Clear(); 
} 

EDIT

Więc List<T> jest typ referencyjny, narażasz się letterList w stosie. W ten sposób przenosisz wartość odniesienia List<T> w stosie pozycja. Tak więc zmienna letterList odnosi się do tego samego obiektu, co element w twoim stosie. Po wyczyszczeniu elementów z listy liter są one również usuwane z elementu stosu.

Sprawdź co jest Reference Types

+1

Żadna z odpowiedzi nie wyjaśnia OP "Kiedy wyczyściłem listę, pierwszy indeks mojego stosu znika, ponieważ przeszedł przez referencję. Czy się mylę? Ponieważ nie wiem, dlaczego tak się dzieje "! –

+0

@ Am_I_Helpful Myślę, że operacja zrozumie, dlaczego wartości są usuwane ze swoich list w stosie. Jeśli tego nie zrozumie, napiszę trochę wyjaśnienia. – mybirthname

-1

można również należy, że jako

Stack<List<HufmannLetter>> steps = new Stack<List<HufmannLetter>>(); 

while(true) 
{ 
var tempList = new List<HufmannLetter>; 
tempList.add("asd"); 
steps.push(tempList); 
} 

lub można spróbować

steps.push(tempList.ToList()); 
    tempList.Clear(); 
+0

To jest ta sama odpowiedź co botond.botos, która została podana przed 6 min. – mybirthname

+0

Tak, ale proszę sprawdź drugą część –

1

List<> jest zmienny typ referencyjny.

Po przekazaniu metody List<> należy przekazać kopię numeru o numerze referencyjnym. Po prostu powiedz, która jest List<>. To nie skopiuje (sklonuje) całej zawartości List<>.

Kiedy można umieścić (Push) do List<> na Stack<>, co Stack<> naprawdę trzyma to kopia odniesienie do tej instancji List<>. Jeśli ta instancja zostanie później zmodyfikowana, na przykład z .Add("asd") lub z .Clear(), ta "mutacja" będzie widoczna niezależnie od tego, czy podążasz za referencją przechowywaną przez Stack<> lub inną referencję, którą masz, ze zmiennej lokalnej. Oba odnośniki "wskazują" na to samo wystąpienie List<>.

Kiedy w kodzie, można powiedzieć:

letterList.Clear(); // do not change reference, follow reference and mutate the instance it refers to 

które będą modyfikować (mutacji) istniejąca instancja List<> więc staje się pusta. Ta zmiana będzie widoczna dla każdego, kto odwołuje się do tej konkretnej instancji List<>.

Jeśli zamiast tego zrobił:

letterList = new List<string>(); // create new instance, change reference to point there (reference assignment), old instance is unchanged 

że musiałby „przeniesiony” odniesienie letterList wskazywać na nowy instancji List<>. Nie wpłynie to na osoby z innymi odniesieniami do "starej" instancji.


Tytuł mijają Odniesienia Wykorzystanie jest mylące. Powinny to być Typy Odniesienia i Przechodzące Referencje lub coś w tym stylu.