Sequential Lists

If you need a collection that stores data in a sequential basis, you can use a Queue which is a first-in, first-out (FIFO) or Stack which is a last-in, first-out (LIFO).  Queue’s most important properties and methods are: Count, Dequeue(), Enqueue(), and Peek().  Stack’s most important properties and methods are: Count, Pop(), Push(), and Peek().

Dictionaries

Dictionaries are another type of collections that are used to store key/value pairs.  The most basic of all dictionary classes that are available in .NET Framework is the Hashtable class.

Hashtable emailLookup = new Hashtable();

// using Add() method
// where 1st parameter is the key and 2nd parameter is the value
emailLookup.Add("jdoe@company.com", "Doe, John");

// using indexer to add key/value pair
emailLookup["jdoe@company.com"] = "Doe, John";

// using indexer to access data
Console.WriteLine(emailLookup["jdoe@company.com"]);

// iterating through the entries in the dictionary
foreach (DictionaryEntry entry in emailLookup)
{
  Console.WriteLine(entry.Value);
}

All dictionary classes support the IDictionary interface which derives from ICollection interface.  IDictionary’s most important properties and methods are: Keys, Values, Add(), Clear(), Contains(), GetEnumerator(), and Remove()Hashtable also has additional methods for testing existence of keys and values: ContainsKey() and ContainsValue().

Hashtable and Equality

The Hashtable uses a hash value, an integer, to aid in the storage of its keys.  It uses the GetHash() method that the Object class supports to test for equality.  The Object.GetHash() method returns a hash value that is unique to the object.  For String class, this GetHash() method is overridden so that two strings with the same text will be equal even though they are different instances. 

Care should be taken that when creating your own class that will be stored in a Hashtable that you override the GetHash() method if the test for equality is wrong.  You also might need to override the Equals() method because if the Hashtable finds that the two objects have same hash value, it will call their Equals() method to see if they are in fact equal.  The Object.Equals() method returns false if the two objects are different instances of the same class.

public class Dog
{
  string _name;

  public Dog(string name)
  {
    _name = name;
  }

  public override int GetHashCode()
  {
    return name.GetHashCode();
  }

  public override bool Equals(object obj)
  {
    Dog otherDog = obj as Dog;
    if (otherDog == null) return false;
    return otherDog.name == name;
  }
}

Another way to specify your own equality comparison is through the IEqualityComparer interface and this is useful if you do not want to change your classes to override the GetHash() and Equals() methods.

public class InsensitiveComparer : IEqualityComparer
{
  CaseInsensitiveComparer _comparer = new CaseInsensitiveComparer();

  public int GetHashCode(object obj)
  {
    return obj.ToString().ToLowerInvariant().GetHashCode();
  }

  public new bool Equals(object x, object y)
  {
    if (_comparer.Compare(x, y) == 0)
    {
      return true;
    }
    else
    {
      return false;
    }
  }
}

// to use the InsensitiveComparer class
Hashtable dehash = new Hashtable(new InsensitiveComparer());
dehash["First"] = "1st";
dehash["Second"] = "2nd";
dehash["Third"] = "3rd";
dehash["Fourth"] = "4th";
dehash["fourth"] = "4th";
Console.WriteLine(dehash.Count); // 4