programowanieProgramista aplikacji Desktop w Visual Basic

Jak są realizowane i używane kolekcje typu Queue i Stack w Visual Basic, kiedy wybierać każdą z struktur i na co ważne jest, aby zwrócić uwagę przy pracy z kolejkami i stacjami?

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź.

Historia pytania:

Kolekcje Queue i Stack to podstawowe struktury danych, które według zasad FIFO (First-In-First-Out) i LIFO (Last-In-First-Out) są odpowiednio zaimplementowane. Są one szeroko stosowane od czasów klasycznego VB6, a od pojawienia się VB.NET te struktury stały się standardowymi klasami. Queue jest przydatna w scenariuszach, gdzie elementy muszą być przetwarzane w kolejności przybycia (np. kolejka zadań), a Stack — gdy ostatnio dodany element musi być przetworzony przed innymi (np. stos wywołań lub cofanie działań).

Problem:

Często błędnie wybiera się niewłaściwą strukturę dla danej zadania lub używa się ich w sposób niebezpieczny w scenariuszach wielowątkowych. Pojawiają się również błędy związane z wydobywaniem z pustego stosu lub kolejki, co powoduje wyjątki.

Rozwiązanie:

W Visual Basic do pracy z tymi strukturami istnieją odpowiednie klasy:

  • System.Collections.Queue
  • System.Collections.Stack

Przykład pracy z kolejką i stosem:

' Praca z kolejką Dim q As New Queue() q.Enqueue("Pierwszy") q.Enqueue("Drugi") Dim item = q.Dequeue() ' item = "Pierwszy" ' Praca ze stosem Dim s As New Stack() s.Push("A") s.Push("B") Dim top = s.Pop() ' top = "B"

Kluczowe cechy:

  • Queue zapewnia porządek FIFO, Stack — LIFO.
  • Aby uzyskać dostęp do pierwszego elementu, używa się Peek(), do usunięcia — Dequeue()/Pop().
  • Należy sprawdzić właściwość Count, aby zapobiec błędom podczas wydobywania z pustej kolekcji.

Pytania z podchwytliwością.

1. Czy można zmieniać kolekcję Queue lub Stack w trakcie iteracji po niej za pomocą For Each?

Nie, zmiana (dodawanie lub usuwanie elementów) kolekcji w trakcie jej przeglądania za pomocą For Each prowadzi do InvalidOperationException.

Przykład kodu:

Dim q As New Queue() q.Enqueue(1) q.Enqueue(2) For Each elem In q q.Enqueue(3) ' spowoduje wyjątek podczas iteracji Next

2. Co zwróci metoda Peek() dla pustego Queue lub Stack?

Peek wyrzuca wyjątek InvalidOperationException, jeśli kolekcja jest pusta, a nie zwraca wartości domyślnej.

Przykład kodu:

Dim st As New Stack() Dim first As Object = st.Peek() ' Wyjątek!

3. Jaka jest różnica między Queue(Of T) a Queue i dlaczego warto preferować kolekcje ogólne?

Queue(Of T) jest wersją generyczną Queue, jest typowo bezpieczna i pozwala uniknąć boxing/unboxing. Zawsze lepiej jest wybierać ją przy pracy z określonymi typami.

Dim numbers As New Queue(Of Integer)() numbers.Enqueue(5) ' Tylko Integer

Typowe błędy i antywzorce

  • Próba wydobycia elementu z pustego Queue/Stack bez sprawdzenia Count.
  • Użycie nie-generycznych kolekcji przy istniejącej kolejce lub stosie z określonym typem danych (utratę bezpieczeństwa typów, błędy rzutowania typów).
  • Modyfikacja kolekcji w trakcie iteracji.

Przykład z życia

Negatywny przypadek

W aplikacji, w której wdrożono kolejkę drukowania dokumentów, programista przechowuje zadania drukowania w Stack, a nie w Queue. W rezultacie dokumenty są drukowane w odwrotnej kolejności (ostatni dodany jako pierwszy jest przetwarzany).

Plusy:

  • Prosta implementacja, wszystkie standardowe operacje są dostępne.

Minusy:

  • Naruszenie logiki pracy — użytkownik oczekuje przetwarzania dokumentów w kolejności dodania, a otrzymuje odwrotne zachowanie.
  • Pojawia się zamieszanie w kolejności zdarzeń i pojawiają się negatywne opinie od użytkowników.

Pozytywny przypadek

Ten sam projekt zmienia Stack na Queue do przechowywania zadań drukowania. Teraz dokumenty są drukowane po kolei od lewej do prawej, zgodnie z oczekiwaniami użytkownika.

Plusy:

  • Zachowanie odpowiada oczekiwaniom użytkowników.
  • Ułatwia to wsparcie i testowanie.

Minusy:

  • Przy niewłaściwym zarządzaniu dostępem do kolejki mogą wystąpić wyścigi (można to rozwiązać za pomocą kolekcji bezpiecznych dla wątków lub synchronizacji).