Niektórzy programiści twierdzą, że lepiej jest przekazywać parametry IEnumerable<T>
przez przekazywanie implementacji takich jak List<T>
, a jednym z popularnych powodów jest to, że interfejs API jest od razu dostępny w większej liczbie scenariuszy, ponieważ więcej zbiorów będzie kompatybilnych z IEnumerable<T>
niż jakakolwiek inna konkretna implementacja, np List<T>
.Czy T [] nie jest lepszy niż IEnumerable <T> jako typ parametru? (Biorąc pod uwagę wyzwania związane z nawiercaniem)
Im więcej nurkuję w wielowątkowych scenariuszach rozwoju, tym bardziej zaczynam myśleć, że IEnumerable<T>
nie jest właściwym typem, a postaram się wyjaśnić, dlaczego poniżej.
Czy otrzymałeś następujący wyjątek podczas wyliczania kolekcji?
Kolekcja została zmodyfikowana; operacja wyliczania może nie zostać wykonana. (InvalidOperationException)
Zasadniczo co powoduje to, dostaniesz kolekcję na jednym wątku, podczas gdy ktoś inny modyfikuje kolekcji na innym wątku.
Aby obejść ten problem, że następnie wywołano zwyczaj zrobić zdjęcie gromadzenia przed wymienić go przez przekształcenie kolekcję tablicy wewnątrz metody, na przykład:
static void LookAtCollection(IEnumerable<int> collection)
{
foreach (int Value in collection.ToArray() /* take a snapshot by converting to an array */)
{
Thread.Sleep(ITEM_DELAY_MS);
}
}
pytanie jest to. Czy nie lepiej jest kodować w kierunku tablic zamiast wyliczeń jako ogólną zasadę, nawet jeśli oznacza to, że osoby dzwoniące są teraz zmuszone do konwersji swoich kolekcji na tablice przy korzystaniu z interfejsu API?
Czy to nie jest czystsze i bardziej kuloodporne? (Typ parametr jest tablicą zamiast)
static void LookAtCollection(int[] collection)
{
foreach (int Value in collection)
{
Thread.Sleep(ITEM_DELAY_MS);
}
}
Tablica spełnia wszystkie wymagania jest przeliczalny i stałej długości, a rozmówca jest świadom faktu, że będzie działać na migawce kolekcji w tym momencie, co może zaoszczędzić więcej błędów.
Jedyną lepszą alternatywą, którą mogę teraz znaleźć, jest IReadOnlyCollection, która będzie jeszcze bardziej odporna na pociski, ponieważ kolekcja jest również dostępna tylko w trybie "zawartość-przedmiot".
EDIT:
@DanielPryden warunkiem link do bardzo ładnej artykule "Arrays considered somewhat harmful". I komentarze pisarza "Rzadko potrzebuję kolekcji, która ma dość sprzeczne właściwości bycia całkowicie zmiennym, a jednocześnie utrwalonym rozmiarem" i "W prawie każdym przypadku istnieje lepsze narzędzie do używaj niż tablicy. " rodzaj przekonania mnie, że tablice nie są tak blisko srebrnej kuli, jak się spodziewałem, i zgadzam się z ryzykiem i lukami. Myślę, że teraz interfejs IReadOnlyCollection<T>
jest lepszą alternatywą niż zarówno tablica, jak i IEnumerable<T>
, ale w pewnym sensie pozostawia mi to pytanie teraz: Czy wywoływacz wymusza na nim użycie parametru o typie IReadOnlyCollection<T>
w deklaracji metody? A może dzwoniący nadal może decydować, która implementacja IEnumerable<T>
przejdzie do metody, która patrzy na kolekcję?
Dzięki za wszystkie odpowiedzi. Wiele nauczyłem się z tych reakcji.
Nie, ta sama łódź. Możesz wkręcić z tablicą _elements_ w drugim wątku. Nawet kod, który wysłałeś z '.ToArray' nie jest bezpieczny dla wątków, jeśli kolekcja zmienia się podczas iteracji, aby przekonwertować ją do tablicy. Najlepszym rozwiązaniem jest udokumentowanie (podpis metody, dokumenty itp.) Faktu, że wybierasz metodę gwintowania i pozostawiasz odpowiedzialność za dzwoniącego, aby zapewnić ci kolekcję, z którą można pracować w sposób gwintowany. Pozwól mu zrobić kopie (lub zapewnij bezpieczną kolekcję). Jeśli dadzą ci śmieci, dajesz im błędy "InvalidOperationException". –
[Lock vs. ToArray for thread safe dostęp do listy kolekcji List] (http://stackoverflow.com/questions/3128889/lock-vs-toarray-for-thread-safe-foreach-access-of-list-collection) –
Zapomniałem wspomnieć, że możesz tworzyć sygnatury swoich metod, żądać jakiegoś zbioru wątków lub innego mechanizmu blokującego, ale to oznacza, że będziesz musiał narzucić ten mechanizm swoim rozmówcom. EDYCJA: Możesz także wykonać kopię _ przed rozpoczęciem pracy w dodatkowe wątki; to kopiowanie byłoby synchroniczne z kodem wywołującym. Jedyną możliwą przyczyną problemów z wątkami będzie to, że wywołujący wykonuje również operacje gwintowania w tym samym zbiorze (ja jestem z łodzi, która utrzymuje ją w prostocie i po prostu pozostawia odpowiedzialność rozmówcy, ale to zależy od zamierzonego API/usage) –