2010-02-01 7 views
24

Mam klasę, która utrzymuje listę obiektów innej klasy. Lista obiektów jest własnością publiczną. Chciałbym, aby uniemożliwić użytkownikom dodawanie i usuwanie obiektów bezpośrednio do listy tak:Czy istnieje interfejs kolekcji .NET, który uniemożliwia dodawanie obiektów?

 MyObject.MyListProperty.Add(object); 

Zamiast tego chcę, żeby wykorzystać metodę, która będzie wewnętrznie zrobić niektóre przetwarzania, a następnie dodać obiekt do listy.

Mam kilka pomysłów:

  • stworzyć potomka List<T> i zastąpić dodawać i usuwać
  • powrotną świeżą kopię listy poprzez własności getter (lista jest stosunkowo krótki, nie dłuższy niż 30 obiekty)

Czy istnieje interfejs kolekcji, który nie ma opcji Dodaj i usuń?

Edit:
mam zamiar iść z ReadOnlyCollection<T>. Powodem jest to, że kolekcja zapakowanych może być aktualizowana, a zmiany będą natychmiast widoczne w obiekcie tylko do odczytu (zobacz przykłady kodu MSDN dla ReadOnlyCollection<T> i AsReadOnly()). Dzięki temu lista tylko do odczytu może zostać utworzona tylko raz.

Problem z IEnumerable polega na tym, że obiekt może zostać bezpośrednio przeniesiony do oryginalnego List<T>, a następnie bezpośrednio.

+0

Ja również poszukuje tego +1 – Ravisha

Odpowiedz

36

Można użyć ReadOnlyCollection - owinąć swoją kolekcję w tym i zwróci ReadOnlyCollection użytkownikom swojej klasie:

return new ReadOnlyCollection(innerCollection); 

albo stosując metodę AsReadOnly klasy List<T>:

return innerCollection.AsReadOnly(); 

IEnumerable Interfejs zrobi to, czego potrzebujesz, ponieważ ma tylko jednego użytkownika o numerze GetEnumerator(), który pozwala tylko na powtarzanie pozycji.

+2

AsReadOnly (http://msdn.microsoft.com/en-us/library/e78dcd75. aspx) nie jest Linq –

+0

Dzięki za poprawkę - naprawiono! – Oded

+0

'IReadOnlyCollection ' i 'AsReadOnly' akceptuje tylko' IList '. Czy istnieje również rozwiązanie dla 'ICollection '? – Shimmy

0

Można po prostu dać im obiekt, który zawsze zwraca moduł wyliczający, którego mogą użyć do uzyskania dostępu do struktury?

5

Możliwe, że metoda AsReadOnly zrobi lewę, aby wydać publicznie tylko instancję "tylko do odczytu".

Inaczej IEnumerable<T> nie ma Add ani Remove, więc można zrobić coś takiego:

private List<int> _myList; 
public IEnumerable<int> MyList 
{ 
    get 
    { 
     return this._myList.ToList(); 
    } 
} 

wolałbym pójść do IEnumerable<T> (+ kopia) jak dla ReadOnlyCollection<T>, ponieważ: zmiany na liście podstawowej (z której twoja kolekcja tylko do odczytu jest tworzona) natychmiast pojawi się w twojej instancji kolekcji tylko do odczytu. może to spowodować problemy blokujące i straaange :)

+0

dlaczego 'zwraca this._myList.ToList();', a nie 'zwraca this._myList;' –

+0

Co z 'IList ' i 'ToArray'? Najlepsze z obu światów, nie? –

+0

IList ma metodę dodawania, więc lista nie będzie tylko do odczytu, i możesz zmienić zawartość tablicy (nie to, które wpłynęłoby na tę klasę, ponieważ tablica jest kopią). Jedynym interfejsem, który rozwiązuje problem OP jest IEnumerable –

5

Twój Najprostszym rozwiązaniem byłoby, aby odsłonić swoją listę jako jeden z następującym IEnumerable, ICollectionReadOnlyCollection poprzez własność publiczną.

Możesz więc utworzyć własną listę type, która ujawnia Twoją Items jako jedną z powyższych, ale ma wewnętrzną metodę dodawania, np.

public class MyList<MyType> 
{ 
    private List<MyType> items; 

    public MyList() 
    { 
     items = new List<MyType>(); 
    } 

    public IEnumerable Items { get { return items.AsEnumerable(); } } 
    public Add(MyType item) 
    { 
     // do internal processing 
     items.Add(item); 
    } 
} 
+0

Chłodne +1 za wyjaśnienie – Ravisha

+3

Należy pamiętać, że nie uniemożliwia to przeniesienia kolekcji z powrotem na listę i wywołanie Dodaj na niej. ReadOnlyCollection to droga, którą należy przejść, jeśli naprawdę trzeba zapobiec dodawaniu. Ponadto, nie ma potrzeby wywoływania items.AsEnumerable i nie sądzę, że skompiluje się to tak, jak napisano, ponieważ AsEnumerable() zwróci IEnumerable , a Items zostanie wpisane jako IEnumerable. –

+0

@Jamie 'IEnumerable ' dziedziczy po 'IEnumerable', więc się skompiluje, ale zgadzam się, że powinny zwrócić IEnumerable , a AsEnumerable jest zbędne. –

2

Po wyjęciu z pudełka, tylko IEnumerable<T> zapewni to bez narażania żadnych Add i Remove publicznych metod, które mogą oszukać klienta na uzyskanie wyjątek czasu wykonywania.

Jeśli chcesz, aby publiczny interfejs API wyraźnie wskazywał, że kolekcja jest tylko do odczytu i potrzebujesz narzędzia indeksującego, będziesz musiał napisać własne opakowanie wokół istniejącego List<T> lub T[].

+0

'IEnumerable ' nie obsługuje dostępu losowego –

0

ICollection (wersja non-generic) dostał tylko IEnumerable + Policz

Powiązane problemy