Monday, 17 December 2012

c sharp programming

KeyedCollection<TKey,TItem> and DictionaryBase

KeyedCollection<TKey,TItem> subclasses Collection<TItem>. It both adds and sub-
tracts functionality. What it adds is the ability to access items by key, much like with
a dictionary. What it subtracts is the ability to proxy your own inner list.

A keyed collection has some resemblance to an OrderedDictionary in that it com-
bines a linear list with a hashtable. However, unlike OrderedDictionary, it doesn’t
implement IDictionary and doesn’t support the concept of a key/value pair. Keys
are  obtained  instead  from  the  items  themselves:  via  the  abstract  GetKeyForItem
method. This means  enumerating  a keyed  collection  is  just  like  enumerating  an
ordinary list.
KeyedCollection<TKey,TItem>  is  best  thought  of  as  Collection<TItem>  plus  fast
lookup by key.
Because it subclasses Collection<>, a keyed collection inherits all of Collection<>’s
functionality, except for the ability to specify an existing list in construction. The
additional members it defines are as follows:
public abstract class KeyedCollection <TKey, TItem> : Collection <TItem>
  // ...
  protected abstract TKey GetKeyForItem(TItem item);
  protected void ChangeItemKey(TItem item, TKey newKey);
  // Fast lookup by key - this is in addition to lookup by index.
  public TItem this[TKey key] { get; }
  protected IDictionary<TKey, TItem> Dictionary { get; }
}


GetKeyForItem is what the implementer overrides to obtain an item’s key from the
underlying object. The ChangeItemKey method must be called if the item’s key prop-
erty changes,  in order to update the  internal dictionary. The Dictionary property
returns the internal dictionary used to implement the lookup, which is created when
the  first  item  is  added.  This  behavior  can  be  changed  by  specifying  a  creation
threshold  in  the constructor, delaying  the  internal dictionary  from being created
until the threshold is reached (in the interim, a linear search is performed if an item
is requested by key). A good reason not to specify a creation threshold is that having
a  valid  dictionary  can  be  useful  in  obtaining  an  ICollection<>  of  keys,  via  the
Dictionary’s  Keys  property.  This  collection  can  then  be  passed  on  to  a  public
property.
The most common use for KeyedCollection<,> is in providing a collection of items
accessible both by index and by name. To demonstrate this, we’ll revisit the zoo,
this time implementing AnimalCollection as a KeyedCollection<string,Animal>:
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)
  {
    Name = name; Popularity = popularity;
  }
}
public class AnimalCollection : KeyedCollection <string, Animal>
{
  Zoo zoo;
  public AnimalCollection (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;
  }
  // The following methods would be implemented as in the previous example
  protected override void InsertItem (int index, Animal item)...
  protected override void SetItem (int index, Animal item)...
  protected override void RemoveItem (int index)...
  protected override void ClearItems()...
}


public class Zoo
{
  public readonly AnimalCollection Animals;
  public Zoo() { Animals = new AnimalCollection (this); }
}
class Program
{
  static void Main()
  {
    Zoo zoo = new Zoo();
    zoo.Animals.Add (new Animal ("Kangaroo", 10));
    zoo.Animals.Add (new Animal ("Mr Sea Lion", 20));
    Console.WriteLine (zoo.Animals [0].Popularity);               // 10
    Console.WriteLine (zoo.Animals ["Mr Sea Lion"].Popularity);   // 20
    zoo.Animals ["Kangaroo"].Name = "Mr Roo";
    Console.WriteLine (zoo.Animals ["Mr Roo"].Popularity);        // 10
  }
}


DictionaryBase
The nongeneric  version of  KeyedCollection  is  called  DictionaryBase. This  legacy
class  takes  very  different  in  its  approach:  it  implements  IDictionary  and  uses

clumsy  hook  methods  like  CollectionBase:  OnInsert,  OnInsertComplete,  OnSet,
OnSetComplete, OnRemove, OnRemoveComplete, OnClear, and OnClearComplete (and ad-
ditionally, OnGet). The primary advantage of implementing IDictionary over taking
the KeyedCollection approach is that you don’t need to subclass it in order to obtain
keys. But since the very purpose of DictionaryBase is to be subclassed, it’s no ad-
vantage at all. The improved model in KeyedCollection is almost certainly due to
the  fact  that  it  was  written  some  years  later,  with  the  benefit  of  hindsight.
DictionaryBase is best considered useful for backward compatibility.

No comments:

Post a Comment