Equality Overview |
[This is preliminary documentation and is subject to change.]
Types stored in a CondensedCollection must provide a way for the collection to compare elements for equality, otherwise elements will not be deduplicated.
Most common System types in the .NET Framework already perform appropriate equality checks (String, DateTime, the various primitives, etc.) by implementing IEquatableT However, if you're storing your own custom type then you must write code that can determine whether two instances are logically equal.
Consider what happens when you store simple, naive objects in a CondensedCollection:
enum Flavor { Chocolate, Vanilla, Carrot, DevilsFood, RedVelvet } class Cake { public Flavor Flavor { get; } public byte CandleCount { get; } public Cake(Flavor flavor, byte candleCount) { Flavor = flavor; CandleCount = candleCount; } } class Program { static void Main() { var cc = new Condensed.CondensedCollection<Cake>(); cc.Add(new Cake(Flavor.Chocolate, 42)); cc.Add(new Cake(Flavor.Chocolate, 42)); Console.WriteLine(cc.InternPoolCount); // Output: 2 } }
...no deduplication is performed! The collection is broken because, by default, reference types check for equality by looking to see if two variables point to the same object instance. Because we create two instances in the example above, we get two distinct values stored in the collection's intern pool.
We will modify our Cake class to get equality behavior that we're looking for. Overrides must be provided for:
Implementing IEquatableT is also recommended, though not strictly required. Our corrected Cake class now looks like this:
class Cake : IEquatable<Cake> { public Flavor Flavor { get; } public byte CandleCount { get; } public Cake(Flavor flavor, byte candleCount) { Flavor = flavor; CandleCount = candleCount; } public override int GetHashCode() { unchecked { int hash = 17; hash = hash * 23 + Flavor.GetHashCode(); hash = hash * 23 + CandleCount.GetHashCode(); return hash; } } public override bool Equals(object obj) { return Equals(obj as Cake); } public bool Equals(Cake other) { return (Flavor == other.Flavor && CandleCount == other.CandleCount); } }
Now the CondensedCollection will properly deduplicate our identical cake objects.
The GetHashCode implementation above is inspired by a StackOverflow answer provided by the legendary Jon Skeet. |
Alternatively, if you would rather not modify your class (or if you don't have control over its implementation) then you can create an IEqualityComparerT implementation for your type and then feed it into the CondensedCollection's constructor.