title: HashSets don't keep the elements unique if you mutate their identity
body: <p>When working with <code>HashSets</code> in C#, I recently came across an annoying problem: <code>HashSets</code> don't guarantee unicity of the elements; they are not Sets. What they do guarantee is that when <code>Add(T item)</code> is called the item is not added if for any item in the set <code>item.equals(that)</code> is <code>true</code>. This holds no longer if you manipulate items already in the set. A small program that demonstrates (copypasta from my Linqpad):</p>
  
  <pre><code>void Main()
  {
      HashSet&lt;Tester&gt; testset = new HashSet&lt;Tester&gt;();
      testset.Add(new Tester(1));
      testset.Add(new Tester(2));
      foreach(Tester tester in testset){
        tester.Dump();
      }
      foreach(Tester tester in testset){
        tester.myint = 3;
      }
      foreach(Tester tester in testset){
        tester.Dump();
      }
      HashSet&lt;Tester&gt; secondhashset = new HashSet&lt;Tester&gt;(testset);
      foreach(Tester tester in secondhashset){
        tester.Dump();
      }
  }
  
  class Tester{
    public int myint;
  
    public Tester(int i){
      this.myint = i;
    }
  
    public override bool Equals(object o){
      if (o== null) return false;
      Tester that = o as Tester;
      if (that == null) return false;
      return (this.myint == that.myint);
    }
  
    public override int GetHashCode(){
      return this.myint;
    }
  
    public override string ToString(){
      return this.myint.ToString();
    }
  }
  </code></pre>
  
  <p>It will happily manipulate the items in the collection to be equal, only filtering them out when a new HashSet is built. What is advicible when I want to work with sets where I need to know the entries are unique? Roll my own, where Add(T item) adds a copy off the item, and the enumerator enumerates over copies of the contained items? This presents the challenge that every contained element should be deep-copyable, at least in its items that influence it's equality.</p>
  
  <p>Another solution would be to roll your own, and only accepts elements that implement INotifyPropertyChanged, and taking action on the event to re-check for equality, but this seems severely limiting, not to mention a whole lot of work and performance loss under the hood.</p>
  
  <p>Yet another possible solution I thought of is making sure that all fields are readonly or const in the constructor. All solutions seem to have very large drawbacks. Do I have any other options?</p>