KeyedCollection<TKey,TItem>
namespace System.Collections.ObjectModel
{
public abstract class KeyedCollection<TKey, TItem> : Collection<TItem>
{
protected KeyedCollection();
protected KeyedCollection(IEqualityComparer<TKey> comparer);
protected KeyedCollection(IEqualityComparer<TKey> comparer, int dictionaryCreationThreshold);
public IEqualityComparer<TKey> Comparer { get; }
protected IDictionary<TKey, TItem> Dictionary { get; }
public bool Contains(TKey key);
public bool Remove(TKey key);
public TItem this[TKey key] { get; }
protected void ChangeItemKey(TItem item, TKey newKey);
protected abstract TKey GetKeyForItem(TItem item);
protected override void InsertItem(int index, TItem item);
protected override void SetItem(int index, TItem item);
protected override void RemoveItem(int index);
protected override void ClearItems();
}
}
- 키 기반 컬렉션을 대표
- Collection<TItem>의 파생 클래스
- 추가된 기능: 키로 접근하는 능력
- 제거된 기능: 내부 목록의 프록시가 되는 능력
반응형
- 선형 목록과 헤시테이블을 결합
* OrderedDictionary와 달리 IDictionary를 구현하지 않고, 키-값 쌍이라는 개념을 지원하지 않음
* 요소에 키가 따로 있는 것이 아니라, 요소 자체에서 키를 얻음
- 기존 목록을 받는 생성자는 제공하지 않음
- GetKeyForItem
* 바탕 객체로부터 항목의 키를 계산해서 돌려줌
* 커스텀 컬렉션 클래스 작성자는 이 추상 메서드를 반드시 구현해야 함
- ChangeItemKey
* 항목의 키를 변경하는데 쓰임(내부 사전 갱신을 위해)
- Dictionary
* 조회를 구현하는 데 쓰이는 내부 사전을 돌려줌
- 컬렉션 생성시 생성 문턱값(Creation Threshold) 설정 가능
* 요소 개수가 해당 문턱값에 도달해야 내부 사전이 생성됨
* 그 이전에는 키 기반 조회를 선형 검색으로 해결함
- Collection<T>에서 다뤘던 예제의 KeyedCollection<TKey,TItem> 버전
namespace Practice
{
class Program
{
public class Animal
{
string name;
public string Name
{
get { return name; }
set
{
if(Zoo != null)
{
Zoo.Animals.NotifyNameChange(this, value);
}
name = value;
}
}
public int popularity;
public Zoo Zoo { get; internal set; }
public Animal(string name, int popularity)
{
this.Name = name;
this.popularity = popularity;
}
}
public class AnimalColletion : KeyedCollection<string, Animal>
{
Zoo zoo;
public AnimalColletion(Zoo zoo)
{
this.zoo = zoo;
}
internal void NotifyNameChange(Animal a, string newName)
{
this.ChangeItemKey(a, newName);
}
protected override string GetKeyForItem(Animal item)
{
return item.Name;
}
protected override void InsertItem(int index, Animal item)
{
base.InsertItem(index, item);
item.Zoo = zoo;
}
protected override void SetItem(int index, Animal item)
{
base.SetItem(index, item);
item.Zoo = zoo;
}
protected override void RemoveItem(int index)
{
this[index].Zoo = null;
base.RemoveItem(index);
}
protected override void ClearItems()
{
foreach (var item in this)
{
item.Zoo = null;
}
base.ClearItems();
}
}
// AnimalCollection을 노출하는 클래스
public class Zoo
{
public readonly AnimalColletion Animals;
public Zoo()
{
Animals = new AnimalColletion(this);
}
}
static void Main(string[] args)
{
Zoo zoo = new Zoo();
zoo.Animals.Add(new Animal("개", 20));
zoo.Animals.Add(new Animal("고양이", 50));
foreach (var item in zoo.Animals)
{
Console.WriteLine($"{item.Name} : {item.popularity}");
}
Console.WriteLine(zoo.Animals[0].Name);
Console.WriteLine(zoo.Animals["개"].popularity);
zoo.Animals["고양이"].Name = "닭";
Console.WriteLine(zoo.Animals["닭"].popularity);
}
}
}
DictionaryBase 클래스
- KeyedCollection의 비제네릭 버전
- IDictionary를 구현
* 클래스 파생 없이도 키를 얻을 수 있지만 기반 클래스 용도로는 적절하지 못하다
- CollectionBase같은 On~ 후킹 메서드 사용
- 이건 하위 호환으로 남겨두고, 그냥 KeyedCollection 씁시다.
반응형
'C#' 카테고리의 다른 글
[C#] IStructuralEquatable, IStructuralComparable (0) | 2023.10.08 |
---|---|
[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#] Collection<T>, CollectionBase, ReadOnlyCollection<T> (0) | 2023.09.28 |
[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 |