2013-12-10 16 views
6

Możesz załadować broń i celować, ale chcę zrozumieć, dlaczego nie powinieneś tego robić.Lista niestandardowa (pochodna) <T>

Stworzyłem klasę niestandardową zaprojektowany aby zastąpić wszystkie wystąpienia List (który używam aktualizacji obiektów XML za nimi):

public class ListwAddRemove<T> : List<T> { 
    public event EventHandler<ListModifyEventArgs> OnAdd; 
    public event EventHandler<ListModifyEventArgs> OnRemove; 

    new public void Add(T o) { 
     base.Add(o); 

     if (OnAdd != null) { 
      OnAdd(this, new ListModifyEventArgs(o)); 
     } 
    } 

    new public void Remove(T o) { 
     base.Remove(o); 

     if (OnRemove != null) { 
      OnRemove(this, new ListModifyEventArgs(o)); 
     } 
    } 
} 

Chodzi o to, kiedy tylko dodać lub usunąć element z tej listy mój powiązane zdarzenia zostaną uruchomione i automatycznie zajmie się XML.

To działa jak czar, na razie tak dobrze.

Ale jak obsługiwać konwersję między object.ToList() i mojej wersji pochodnej?

Wiele osób twierdzi, że powinieneś czerpać z kolekcji zamiast ... dlaczego?

+11

Czy słyszałeś o ObservableCollection? http://msdn.microsoft.com/en-au/library/ms668604(v=vs.110).aspx i http://stackoverflow.com/questions/3167752/is-there-a-way-to-convert -an-obserwowalne-kolekcja-do-listy – Aybe

+0

Używam Windows Forms .Net 3.5 – user1830285

+0

Używanie modyfikatora 'new' do ukrywania członków z klasy bazowej nigdy nie jest dobrym pomysłem. Jeśli naprawdę chcesz wywodzić się z 'List <>', podaj swoim metodom nowe nazwy, takie jak 'AddAndRaiseEvent' lub podobne. Jednak klasa 'List <>' nie jest przeznaczona do tego celu. Istnieją inne klasy, które oferują więcej "wirtualnych" członków, które mają być pomocne przy ich dziedziczeniu. –

Odpowiedz

7

Należy czerpać z Collection<T> ponieważ jest zaprojektowany tak, aby można zastąpić InsertItem i RemoveItem dodać niestandardowe zachowania, takie jak to, co robisz (również SetItem, aby dodać niestandardowe zachowanie przy zmianie istniejącego elementu).

Z tego powodu może być używany jako IList<T>, a każde wstawienie/usunięcie automatycznie zastosuje dostosowanie.

W twoim przypadku każdy, kto rzuci na IList<T> lub na klasę podstawową List<T>, ominie Twoją niestandardową funkcję Dodaj/Usuń.

Collection<T> dostarcza również konstruktora do zawijania istniejącej listy. Możesz odsłonić to ze swojej klasy pochodnej, aby zawinąć listę wygenerowaną przez Enumerable<T>.ToList().

UPDATE

Co składnia narażać konstruktora proszę?

Bardzo prosta:

public class ListwAddRemove<T> : Collection<T> 
{ 
    public ListwAddRemove<T>() 
    { 
    } 

    public ListwAddRemove<T>(IList<T> list) : base(list) 
    { 
    } 

    ... implementation of overrides for InsertItem, SetItem, RemoveItem ... 
} 

następnie używać go w sposób następujący:

IList<SomeType> list = ....ToList(); 
ListwAddRemove<SomeType> myList = new ListwAddRemove<SomeType>(list); 
+0

Każdy, kto rzuci interfejs "IList ", straci nową funkcjonalność, ale tak samo każdy, kto rzuci na bazową klasę 'List ' (jak w odpowiedzi MartinaStettnera). –

+0

"Możesz odsłonić to z klasy pochodnej, aby zawinąć listę wygenerowaną przez" ... Jaką składnię należy odsłonić konstruktor? Lubię tę implementację – user1830285

+0

Jest ok: public ListwAddRemove (lista incomingList): base (incomingList) {} – user1830285

2

Dla jednego,

void DoSomeAddingToList(List<int> list) { 
    list.Add(1); 
} 

var list = new ListwAddRemove<int>(); 
DoSomeAddingToList(list); 

nie wywoła zdarzenia. To może prowadzić do dziwnego efektu, zwłaszcza jeśli nie jesteś jedyną osobą używającą tej klasy.

List<T> definiuje bardzo specyficzne zachowanie dla Add i Remove (ponieważ jest to beton klasy), a użytkownicy mogą liczyć na dokładnie tego zachowania.

Wydaje mi się, że jest to ogólnie prawdą w przypadku używania modyfikatora new, więc należy używać tej funkcji języka z rozwagą, szczególnie w przypadku metod publicznych.

Jak wspomnieli inni, wprowadzenie implementacjiIList<T> (przy użyciu delegacji/agregacji) jest prawdopodobnie lepszym wyborem.