![]() Главная страница Случайная страница КАТЕГОРИИ: АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника |
Типы для создания пользовательских коллекций
Типы коллекций, описанные в предыдущих параграфах, применимы в большинстве стандартных ситуаций. Однако иногда требуется создать собственный тип-коллекцию. Например, в случае, когда изменение коллекции должно генерировать событие, или когда необходима дополнительная проверка данных при помещении их в коллекцию. Для облегчения решения этой задачи платформа.NET предлагает несколько классов, размещённых в пространстве имён System.Collections.ObjectModel. Универсальный класс Collection< T> является настраиваемой оболочкой над классом List< T> [10]. В дополнение к реализации интерфейсов IList< T> и IList, класс Collection< T> определяет четыре виртуальных метода ClearItems(), InsertItem(), RemoveItem(), SetItem() и свойство для чтения Items, имеющее тип IList< T>. Переопределяя виртуальные методы, можно модифицировать нормальное поведение класса List< T> при изменении набора. Рассмотрим пример использования Collection< T>. Пусть класс Track представляет отдельную композицию музыкального альбома. Класс Album наследуется от Collection< Track> и описывает альбом. Виртуальные методы класса Collection< Track> переопределяются, чтобы корректно изменять значение свойства Album у объекта Track. public class Track { public string Title { get; set; } public uint Length { get; set; } public Album Album { get; internal set; } }
public class Album: Collection< Track> { protected override void InsertItem(int index, Track item) { base.InsertItem(index, item); item.Album = this; }
protected override void SetItem(int index, Track item) { base.SetItem(index, item); item.Album = this; }
protected override void RemoveItem(int index) { this[index].Album = null; base.RemoveItem(index); }
protected override void ClearItems() { foreach (Track track in this) { track.Album = null; } base.ClearItems(); } } У класса Collection< T> имеется конструктор, принимающий в качестве аргумента объект, реализующий IList< T>. В отличие от других классов коллекций, этот набор не копируется – запоминается ссылка на него. То есть, изменение набора будет означать изменение коллекции Collection< T> (хотя и без вызова виртуальных методов). Класс ReadOnlyCollection< T> – это наследник Collection< T>, предоставляющий доступ для чтения элементов, но не для модификации коллекции. Конструктор класса принимает в качестве аргумента объект, реализующий IList< T>. Класс не содержит открытых методов добавления или удаления элемента, но можно получить доступ к элементу по индексу и изменить его. var album = new Album { new Track {Title = " Speak To Me", Length = 68}, new Track {Title = " Breathe", Length = 168}, new Track {Title = " On The Run", Length = 230} }; var albumReadOnly = new ReadOnlyCollection< Track> (album); albumReadOnly[1].Title = string.Empty; Класс ObservableCollection< T> – это коллекция, позволяющая отслеживать модификации своего набора данных. Этот класс наследуется от Collection< T> и реализует интерфейс INotifyCollectionChanged, который описывает событие, генерируемое при изменении данных: public interface INotifyCollectionChanged { event NotifyCollectionChangedEventHandler CollectionChanged; } Аргумент события CollectionChanged позволяет узнать, какое действие выполнено над набором данных (добавление, удаление, замена элемента), а также получить информацию о новых или удалённых элементах коллекции. // коллекция album – такая же, как в предыдущем примере var observable = new ObservableCollection< Track> (album); observable.CollectionChanged += (sender, e) => { Console.WriteLine(e.Action); foreach (Track item in e.NewItems) { Console.WriteLine(item.Title); } }; observable.Add(new Track {Title = " Time", Length = 424}); Абстрактный класс KeyedCollection< TKey, TItem> является наследником Collection< T>. Этот класс добавляет возможность обращения к элементу по ключу (как в словарях). При использовании KeyedCollection< TKey, TItem> требуется переопределить метод GetKeyForItem() для вычисления ключа элемента. Для демонстрации применения KeyedCollection< TKey, TItem> модифицируем пример с классами Track и Album: public class Track { private string _title;
public string Title { get { return _title; } set { if (Album! = null & & _title! = value) { Album.ChangeTitle(this, value); // изменение ключа } _title = value; } }
public uint Length { get; set; } public AlbumDictionary Album { get; internal set; } }
public class AlbumDictionary: KeyedCollection< string, Track> { protected override string GetKeyForItem(Track item) { return item.Title; // ключом будет название композиции }
internal void ChangeTitle(Track track, string title) { ChangeItemKey(track, title); // метод меняет ключ элемента }
// методы ClearItems(), InsertItem(), RemoveItem(), SetItem() // реализованы так же, как в классе Album }
// пример использования var album = new AlbumDictionary { new Track {Title = " Speak To Me", Length = 68}, new Track {Title = " Breathe", Length = 168}, new Track {Title = " On The Run", Length = 230} }; album[0].Length = 0; // обращение по индексу album[" Speak To Me" ].Length = 68; // обращение по ключу
|