커스텀화 가능한 컬렉션과 프록시
- 일반적인 컬렉션 클래스들은 바로 인스턴스화 해서 쓸 수 있지만, 세밀한 컨트롤이 불가능함
- 예를 들자면...
* 항목이 추가되거나 제거되면 이벤트를 발동
* 추가 또는 제거된 항목에 맞게 속성들을 갱신
* 규칙에 맞지 않는 연산을 검출하여 예외를 던짐
- System.Collections.ObjectModel 이름 공간 안에는 이런 용도를 위한 클래스들을 제공
* IList<T>나 IDictionary<TKey,TValue>를 구현하는 래퍼(Wrapper)나 프록시(Proxy)
* 메서드들을 바탕 컬렉션에 전달하는 역할
* Add, Remove 같은 연산을 일종의 관문(Gateway) 역할을 하는 가상 메서드에 연결
* 커스텀 컬렉션을 만들 때에는 그 가상 메서드들을 적절히 재정의함으로서 원하는 기능성을 구현
ex) System.Windows.Form 클래스의 Public 컨트롤들의 컬렉션
Collection<T> 클래스
namespace System.Collections.ObjectModel
{
public class Collection<T> : IList<T>, ICollection<T>, IEnumerable<T>, IEnumerable, IList, ICollection, IReadOnlyList<T>, IReadOnlyCollection<T>
{
public Collection();
public Collection(IList<T> list);
public T this[int index] { get; set; }
public int Count { get; }
protected IList<T> Items { get; }
public void Add(T item);
public void Clear();
public bool Contains(T item);
public void CopyTo(T[] array, int index);
public IEnumerator<T> GetEnumerator();
public int IndexOf(T item);
public void Insert(int index, T item);
public bool Remove(T item);
public void RemoveAt(int index);
protected virtual void ClearItems();
protected virtual void InsertItem(int index, T item);
protected virtual void RemoveItem(int index);
protected virtual void SetItem(int index, T item);
}
}
- List<T>에 대한 커스텀화 가능 래퍼
- IList<T>와 IList를 구현, 몇개의 가상 메서드들과 보호된 속성도 정의
- 가상 메서드들은 일종의 관문 역할을 수행
- 커스텀 컬렉션 구현자는 이들을 후킹 지점으로 사용해서 기본 행동 방식을 변경하거나 개선
- IList<T>를 받는 생성자의 경우 주어진 목록을 복사하는 대신, 그냥 자신을 해당 목록의 프록시(Proxy)로 삼음
* 목록에 생긴 변화는 해당 Collection<T>에 반영되며, Collection<T>에 가해진 변형은 해당 목록에도 가해짐
* 단, Collection<T>의 가상 메서드의 호출은 일어나지 않음
CollectionBase 클래스
- Collection<T>의 비제네릭 버전
- 구현해야 할 메서드가 제네릭 버전의 2배
- OnInsert, OnInsertComplete ↔ InsertItem
- OnSet, OnSetComplete ↔ SetItem
- OnRemove, OnRemoveComplete ↔ RemoveItem
- OnClear, OnClearComplete ↔ ClearItem
- 이 클래스를 상속할 때는 형식 있는 메서드도 구현해야 함 (적어도 형식 있는 인덱서와 Add 메서드)
ReadOnlyCollection<T> 클래스
namespace System.Collections.ObjectModel
{
public class ReadOnlyCollection<T> : IList<T>, ICollection<T>, IEnumerable<T>, IEnumerable, IList, ICollection, IReadOnlyList<T>, IReadOnlyCollection<T>
{
public ReadOnlyCollection(IList<T> list);
public T this[int index] { get; }
public int Count { get; }
protected IList<T> Items { get; }
public bool Contains(T value);
public void CopyTo(T[] array, int index);
public IEnumerator<T> GetEnumerator();
public int IndexOf(T value);
}
}
- 기존 컬렉션의 읽기 전용 시각을 제공하는 하나의 래퍼 또는 프록시
- 소비자에게는 읽기 전용 접근만 제공하되, 클래스 자체는 여전히 컬렉션을 내부적으로 수정 할 수 있는 클래스를 만들 때 사용
- 입력 컬렉션을 인수로 받되, 복사본을 사용하는 것이 아니므로 입력된 컬렉션이 변하면 읽기 전용 컬렉션에도 그 변경이 반영됨
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace Practice
{
class Program
{
public static void Main(string[] arg)
{
RocTest rocTest = new RocTest();
Console.WriteLine(rocTest.Names.Count);
rocTest.AddInternally("test");
Console.WriteLine(rocTest.Names.Count);
// 여기서 예외 발생
((IList<string>)rocTest.Names).Add("test");
}
}
public class RocTest
{
List<string> names;
public ReadOnlyCollection<string> Names { get; /*private set;*/ }
public RocTest()
{
names = new List<string>();
Names = new ReadOnlyCollection<string>(names);
}
public void AddInternally(string text)
{
names.Add(text);
}
}
}
'C#' 카테고리의 다른 글
[C#] StringComparer (0) | 2023.10.06 |
---|---|
[C#] IComparer<T>, IComparer, Comparer<T> (0) | 2023.10.04 |
[C#] IEqualityComparer<T>, IEqualityComparer, EqualityComparer (0) | 2023.10.02 |
[C#] KeyedCollection<TKey,TItem>, DictionaryBase (0) | 2023.09.30 |
[C#] SortedDictionary<TKey,TValue>, SortedList<Tkey,TValue>, SortedList (0) | 2023.09.26 |
[C#] OrderedDictionary, ListDictionary, HybridDictionary (0) | 2023.09.24 |
[C#] Dictionary<TKey,TValue>, Hashtable (0) | 2023.09.22 |
[C#] IDictionary<TKey,TValue>, IReadOnlyDictionary<TKey,TValue>, IDictionary (0) | 2023.09.20 |