I need to create a set of unique Font objects each of which should have an associated object. This should be done in a .NET Framework WinForms app. These Font objects come from various sources, and different Font objects can be actually the same - if they have the same name, size, and other characteristics. It seems the Hashtable class can be used for this. Here is a simple test in a brand new WinForms app for .NET Framework:
private void Form1_Load(object sender, EventArgs e)
{
Font font1 = new Font(this.Font, FontStyle.Regular);
Font font2 = new Font("Microsoft Sans Serif", 8.25f);
Hashtable ht = new Hashtable();
ht.Add(font1, 1);
ht.Add(font2, 2);
}
The last statement that adds font2 throws the following exception:
System.ArgumentException HResult=0x80070057 Message=Item has already been added. Key in dictionary: '[Font: Name=Microsoft Sans Serif, Size=8.25, Units=3, GdiCharSet=1, GdiVerticalFont=False]' Key being added: '[Font: Name=Microsoft Sans Serif, Size=8.25, Units=3, GdiCharSet=1, GdiVerticalFont=False]' Source=mscorlib StackTrace: at System.Collections.Hashtable.Insert(Object key, Object nvalue, Boolean add) at System.Collections.Hashtable.Add(Object key, Object value) at Font_Hashtable.Form1.Form1_Load(Object sender, EventArgs e)
This proves that the specialized Font equality comparer is used to check if Font objects are used as Hashtable keys. I wonder - can we really use a Hashtable for this scenario? As I know, .NET Hashtables should compare keys by references if they are objects, and there should be no exception in the code above if this is the case.
The
Hashtablechecks inAddif the key is already contained, then it will throw this exception. Therefore it checks if there is one with the same hashcode. If so it checks if they are equal, first by checking if it's the same same reference(object.ReferenceEquals). If not it checks if they are equal. Either by the givenKeyComaprerin the constructor or byobject.Equals. IfEqualsis overridden,FontoverridesEquals, that one is used.The documentation mentions it also:
Since
GetHashCodeis used first, always overrideEqualsandGetHashCodetogether. Two equal objects must have the same hashcode(but same hashcode doesn't necessarily mean equal).By the way, there is no reason to use the old
Hashtableanymore. Here you should use aDictionary<Font, float>.If you use a
HashTableor a genericDictionary<TKey, TValue>does not make a difference for this issue: both are checking inAddif there is another item with the same hash-code and if so, if both items are equal, then you get thisArgumentException.Both use either the passed custom
IEqalityComparer(constructor) orEquals(if not overriddenobject.Equals, which just compares references).