2010-10-08 11 views
6

Mam więc te klasy, które eksponują kolekcję obiektów podrzędnych.Czy istnieje dobry wzór do ujawnienia kolekcji ogólnej jako readonly?

Nie chcę, aby inne klasy dodawały lub usuwały obiekty z kolekcji, ponieważ muszę je łączyć w zdarzenia w obiektach podrzędnych, tak aby były dodawane lub usuwane. Chcę móc wykonać dodatkowe przetwarzanie. Ale uwielbiam łatwość manipulowania generykami wewnętrznie.

Czy wspomniałem, że jest to aplikacja WPF, więc potrzebuję INotifySupport?

Najlepsze, co mogę wymyślić, to coś takiego.

public class foo : INotifyPropertyChanged 
{ 
    protected List<ChildFoo> _Children = new List<ChildFoo>(); 

    public foo() 
    { 
    } 

    public void AddChild(ChildFoo newChild) 
    { 
     DoAttachLogic(newChild); 
     _Children.Add(newChild); 
     NotifyPropertyChange("Children"); 
    } 

    public void RemoveChild(ChildFoo oldChild) 
    { 
     DoRemoveLogic(oldChild); 
     _Children.Remove(oldChild); 
     NotifyPropertyChange("Children"); 
    } 

    public ChildFoo[] Children 
    { 
     get 
     { 
      return _Children.ToArray(); 
     } 
    } 

} 

Czy istnieją poważne wady tego wzoru, których nie widzę?

Za każdym razem, gdy uzyskuje się dostęp do właściwości Children, otrzymujemy obciążenie związane z przekształcaniem listy w tablicę.

Wszelkie porady na ten temat byłyby świetne.

+1

Nie podnoś wartości NotifyPropertyChange ("Dzieci"), ponieważ obiekt podrzędny został zmieniony. Nie chcesz ponownie wiązać całej kolekcji. –

+2

Zamiast Lista , należy rozważyć ObservableCollection . Implementuje zdarzenia zmiany kolekcji oczekiwane przez usługę WPF. Inną opcją jest bezpośrednie wdrożenie INotifyCollectionChanged. –

+0

Prawo, ale problem z ObservableCollection jest taki, że każdy programista może teraz dodać do kolekcji bezpośrednio, bez użycia metody AddChild(). Gdyby był sposób, aby to zrobić, użyłbym obserwowalnego w mgnieniu oka. –

Odpowiedz

0

Powinieneś używać ObservableCollection jako pola w swojej klasie, wtedy masz pełny dostęp do modyfikacji kolekcji. Następnie wyeksponuj to jako właściwość ReadonlyObservableCollection. A jeśli nie zmienisz samej kolekcji (np. Nr children = new ObservableCollection(), powinieneś zrobić pole tylko do odczytu), to nie potrzebujesz żadnego rodzaju obiektu notifyPropertyChanged na tej właściwości, ponieważ nie zmienia się i kolekcja sama zajmuje się tymi zdarzeniami dla swoich dzieci.

public class Child 
{ 
    public int Value { get; set; } 
} 

class MyClassWithReadonlyCollection 
{ 
    private readonly ObservableCollection<Child> _children = new ObservableCollection<Child>(); 

    public MyClassWithReadonlyCollection() 
    { 
     _children.Add(new Child()); 
    } 

    //No need to NotifyPropertyChange, because property doesnt change and collection handles this internaly 
    public ReadOnlyObservableCollection<Child> Children { get { return new ReadOnlyObservableCollection<Child>(_children); } } 
} 
5

To jest to, co robię dla normalnego kodu:

Public Readonly Property Childern As ObjectModel.ReadOnlyCollection(Of Child) 
    Get 
     Return New ObjectModel.ReadOnlyCollection(Of Child)(_ChildernList) 
    End Get 
End Property 

Dla kodu WPF Chciałbym tylko narazić podklasy ObservableCollection.

+0

-1 do korzystania z VB w odpowiedzi na C# – Tergiver

+0

Mam nadzieję, że nie sugerujesz, że deweloperzy C# nie są wystarczająco inteligentni, aby przeczytać podstawowe. –

+0

Poważnie mogę przeczytać VB po prostu dobrze dziękuję. –

0

Zmieniłem "dodaj dziecko" i "usuń dziecko" na chronione, ponieważ mówisz, że nie chcesz innych zajęć modyfikujących swoją kolekcję. Zmieniłem twoją listę na ObservableCollection, abyś mógł otrzymywać powiadomienia o zmianie kolekcji. Ponieważ używasz IList, nie ma potrzeby wywoływania ToArray(), po prostu dostęp bezpośrednio.

spróbuj tego:

public class foo : INotifyPropertyChanged 
{ 
    protected ObservableCollection<ChildFoo> _Children = new ObservableCollection<ChildFoo>(); 

public foo() { } 

protected void AddChild(ChildFoo oldChild) 
{ 
    DoAttachLogic(newChild); 
    _Children.Add(newChild); 
    NotifyPropertyChange("Children"); 
} 

protected void RemoveChild(ChildFoo oldChild) 
{ 
    DoRemoveLogic(oldChild); 
    _Children.Remove(oldChild); 
    NotifyPropertyChange("Children"); 
} 

public ChildFoo this[int n] 
{ 
    get 
    { 
     return _Children[n]; 
    } 
} 

} 
+0

Chcę, aby ludzie mogli zwiększyć lub zmniejszyć kolekcję, ale potrzebuję ich do przejścia przez klasę, aby to zrobić, więc mogę uruchomić dodatkową logikę na obiektach, które są dodawane/usuwane. –

+0

tak, w zasadzie to, czego chcesz, to opakowanie wokół listy. po prostu zmień chroniony dodatek/usuń na publiczny w kodzie, który dałem, i powinieneś być złoty –

0

Można podklasy BindingList i ustawić AllowNew/AllowRemove false. W swoich metodach dodawania/usuwania dla dzieci można ustawić wartość true, wprowadzić zmiany, a następnie ustawić wartość false. (Oczywiście, musisz również ukryć dostęp do ustawień AllowNew/AllowRemove od osób dzwoniących z zewnątrz).

Inna opcja - podklasa Obserwowalna kolekcja i nadpisywanie metod InsertItem, RemoveItem, itp., Aby zachowywać się jak AddChild/RemoveChild zachowałaby się. Następnie osoby dzwoniące mogą nadal uzyskiwać do niego dostęp w znany sposób, ale nie ominąć niestandardowej logiki.

Podklasy istniejącej klasy kolekcji prawdopodobnie będą łatwiejsze (dla ciebie i konsumenta) niż zawijanie kolekcji w innej klasie.

Powiązane problemy