Korzystam z pętli for lub foreach (nie ma znaczenia), aby przeglądać wszystkie moje obiekty, gdy trzeba je zaktualizować lub narysować. Jednak gdy obiekt zostanie zabity, chcę, aby został ponownie usunięty z kolekcji.
Robię to, dodając obiekt do listy martwych obiektów, a następnie, gdy wszystko zostało narysowane i zaktualizowane, przeglądam wszystko na tej liście, usuwając również obiekty na liście z oryginalnego źródła.
Czy jest na to lepszy sposób?
Odpowiedzi:
Przede wszystkim: terminologia. Jeśli powiesz „lista śmieci”, ludzie pomyślą, że mówisz o śmieciarzu. Nazwijmy to „martwą listą”.
Jak zapewne odkryłeś, stąd twoje pytanie, nie możesz usuwać przedmiotów z kolekcji podczas iteracji. Jeśli Twoja kolekcja jest
List<>
najprostszym sposobem na usunięcie z niej przedmiotów:Pamiętaj, że iterujesz wstecz . Możesz usuwać elementy podczas iteracji do przodu, ale jest to bardziej skomplikowane i wymaga
goto
. Nie możesz tego zrobićforeach
.Możesz wykonać usuwanie oddzielnie od pętli aktualizacji. Lub możesz połączyć go w pętlę aktualizacji. Zawsze wykonuj
RemoveAt
na końcu pętli - po tym punkcie w pętlilist[i]
nie można jej uznać za poprawną (staje się znów ważna przy następnej iteracji).Zauważ też, że każdy obiekt ma swoją własną
IsDead
flagę (jeśli używasz wzorca usuwania, możesz to zrobićIsDisposed
) - tak naprawdę wcale nie musisz utrzymywać „martwej listy”.Używanie flagi na każdym elemencie jest lepsze ze względu na wydajność, ponieważ unikasz konieczności przeszukiwania listy w celu usunięcia. Jest również preferowany przy projektowaniu - oznacza to, że każdy obiekt może łatwo sprawdzić, czy jest martwy - więc nie wywołujesz przypadkowo żadnych metod na nim (jeśli obiekty te implementują wzór jednorazowy, mogą
ObjectDisposedException
w tym przypadku rzucić ).Jeśli masz kolekcję inną niż a
List<>
, usunięcie martwych elementów z tej kolekcji może nadal wymagać utworzenia martwej listy (ponieważ usunięcie podczas iteracji może być niemożliwe). Moim zdaniem, lepiej jest zaprojektować martwą listę tuż przed jej użyciem, iterując kolekcję w poszukiwaniuIsDead
flag, zamiast starać się zachować listę, gdy obiekty są zabijane.Gdy skończysz z martwą listą, powinieneś
Clear()
ją zachować, a następnie pozostawić w pobliżu, aby użyć jej później.źródło
IsDead
Wzór jest funkcjonalnie identyczneIsDisposed
. Semantyczne użycieIsDead
oznacza, że utrzymujesz listę Rysuj / Aktualizuj tych obiektów, które później będą miały usunięte martwe elementy. Wzór usuwania nie oznacza tego. Ponadto wzór utylizacja nie oznacza, że można mieć niezarządzanych zasobów posiadanych przez danego obiektu (który zwykle nie jest odpowiednie dla obiektów rozgrywki).W 99,9% przypadków śmieciarz (GC) zajmie się wszystkim bez żadnych problemów. Po prostu pozwól mu działać po usunięciu / unieważnieniu tych obiektów. Opóźnienie w czyszczeniu zależy od wielu czynników (na przykład, ile bloków pamięci zostało przypisanych), ale zwykle nie musisz o tym nawet wiedzieć, nie mówiąc już o tym. Jest przeznaczony do pracy. Co jest jednym z powodów, dla których używasz C #, a nie C.
Jeśli chodzi o wydajność GC w ogóle, nie przejmuj się nadmiernie, chyba że wiesz (poprzez profilowanie), że tworzy on wąskie gardło - dotyczy to tylko dość wymagających gier. W takim przypadku zajrzyj do GC.Collect () i jego różnych pułapek, abyś wiedział, kiedy należy go użyć. Sugeruję, że googling „force gc xna”, jest tam mnóstwo materiału.
źródło