Есть ли хороший шаблон для представления общей коллекции как только для чтения? - PullRequest
6 голосов
/ 09 октября 2010

Итак, у меня есть эти классы, которые предоставляют коллекцию дочерних объектов.

Я не хочу, чтобы другие классы добавляли или удаляли объекты из коллекций, потому что мне нужно подключаться к событиям в дочерних объектах, чтобы по мере их добавления или удаления я хотел иметь возможность выполнять дополнительную обработку. Но я действительно люблю легкость манипулирования генериками внутри.

Я уже говорил, что это приложение WPF, поэтому мне нужен INotifySupport?

Лучшее, что я могу придумать, это что-то вроде этого.

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();
        }
    }

}

Есть ли серьезные недостатки этого дизайна, которых я не вижу?

Каждый раз, когда осуществляется доступ к свойству Children, мы получаем издержки на преобразование списка в массив.

Любой совет по этому поводу был бы великолепен.

Ответы [ 4 ]

5 голосов
/ 09 октября 2010

Это то, что я делаю для нормального кода:

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

Для кода WPF я бы просто предоставил подкласс ObservableCollection.

0 голосов
/ 09 октября 2010

Вы должны использовать ObservableCollection в качестве поля в вашем классе, тогда у вас будет полный доступ для изменения коллекции. Затем представьте это как ReadonlyObservableCollection через свойство. И если вы не изменяете саму коллекцию (например, нет children = new ObservableCollection(), вы должны сделать поле доступным только для чтения), тогда вам не нужно никакого типа notifyPropertyChanged для этого свойства, поскольку оно не изменяется, и сама коллекция обрабатывает эти события для своих дочерних элементов.

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); } }
}
0 голосов
/ 09 октября 2010

Вы можете создать подкласс BindingList и установить для AllowNew / AllowRemove значение false. В ваших методах Child Add / Remove вы можете установить значение true, внести изменения, а затем вернуть значение false. (Конечно, вам нужно скрыть установленный доступ к AllowNew / AllowRemove и от внешних абонентов).

Другой вариант - создать подкласс Observable collection и переопределить методы InsertItem, RemoveItem и т. Д., Чтобы они вели себя так же, как и AddChild / RemoveChild. Тогда вызывающие абоненты все равно смогут получить к нему доступ привычными способами, но не смогут обойти вашу пользовательскую логику.

Создание подкласса для существующего класса коллекции, вероятно, будет проще (для вас и потребителя), чем перенос коллекции в другой класс.

0 голосов
/ 09 октября 2010

Я изменил «добавить ребенка» и «удалить ребенка» на защищенный, поскольку вы говорите, что не хотите, чтобы другие классы модифицировали вашу коллекцию.Я изменил ваш список на ObservableCollection, чтобы вы могли получать уведомления об изменениях коллекции.Поскольку вы используете IList, нет необходимости вызывать ToArray (), просто получить прямой доступ.

попробуйте это:

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];
    }
}

}
...