[C#] KeyedCollection<TKey,TItem>, DictionaryBase
KeyedCollection<TKey,TItem>
KeyedCollection<TKey,TItem> 클래스 (System.Collections.ObjectModel)
키가 값에 포함되어 있는 컬렉션에 대한 추상 기본 클래스를 제공합니다.
learn.microsoft.com
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 클래스
DictionaryBase 클래스 (System.Collections)
강력한 형식의 키/값 쌍 컬렉션에 대한 abstract 기본 클래스를 제공합니다.
learn.microsoft.com
- KeyedCollection의 비제네릭 버전
- IDictionary를 구현
* 클래스 파생 없이도 키를 얻을 수 있지만 기반 클래스 용도로는 적절하지 못하다
- CollectionBase같은 On~ 후킹 메서드 사용
- 이건 하위 호환으로 남겨두고, 그냥 KeyedCollection 씁시다.