title: Equals/GetHashCode override warning in derived class with no state
body: <p>I've created a strongly-typed, immutable wrapper class for various string IDs that flow through our system</p>
  <h2>The abstract BaseId class:</h2>
  <p>(some error-checking and formatting omitted for brevity...)</p>
  <pre><code>public abstract class BaseId
  {
      // Gets the type name of the derived (concrete) class
      protected abstract string TypeName { get; }
  
      protected internal string Id { get; private set; }
  
      protected BaseId(string id) { Id = id; }
  
      // Called by T.Equals(T) where T is a derived type
      protected bool Equals(BaseId other)
      {
          if (ReferenceEquals(null, other))
              return false;
          if (ReferenceEquals(this, other))
              return true;
          return String.Equals(Id, other.Id);
      }
  
      // warning CS0660 (see comment #1 below)
      //public override bool Equals(object obj) { return base.Equals(obj); }
  
      public override int GetHashCode()
      {
          return TypeName.GetHashCode() * 17 + Id.GetHashCode();
      }
  
      public override string ToString()
      {
          return TypeName + &quot;:&quot; + Id;
      }
  
      // All T1 == T2 comparisons come here (where T1 and T2 are one
      // or more derived types)
      public static bool operator ==(BaseId left, BaseId right)
      {
          // Eventually calls left.Equals(object right), which is
          // overridden in the derived class
          return Equals(left, right);
      }
  
      public static bool operator !=(BaseId left, BaseId right)
      {
          // Eventually calls left.Equals(object right), which is
          // overridden in the derived class
          return !Equals(left, right);
      }
  }
  </code></pre>
  <p>My goal was keep as much of the implementation in the base class so that the derived classes would be small, consisting mostly/entirely of boilerplate code.</p>
  <h2>Example concrete DerivedId class:</h2>
  <p>Note that this derived type defines no additional state of its own. Its purpose is solely to create a strong type.</p>
  <pre><code>public sealed class DerivedId : BaseId, IEquatable&lt;DerivedId&gt;
  {
      protected override string TypeName { get { return &quot;DerivedId&quot;; } }
  
      public DerivedId(string id) : base(id) {}
  
      public bool Equals(DerivedId other)
      {
          // Method signature ensures same (or derived) types, so
          // defer to BaseId.Equals(object) override
          return base.Equals(other);
      }
  
      // Override this so that unrelated derived types (e.g. BarId)
      // NEVER match, regardless of underlying Id string value
      public override bool Equals(object obj)
      {
          // Pass obj or null for non-DerivedId types to our
          // Equals(DerivedId) override
          return Equals(obj as DerivedId);
      }
  
      // warning CS0659 (see comment #2 below)
      //public override int GetHashCode() { return base.GetHashCode(); }
  }
  </code></pre>
  <h2>Each class is generating a compiler warning:</h2>
  <ol>
  <li><p>Not overriding Object.Equals(object o) in BaseId generates a compile warning:<br/><br/>
  <code>warning CS0660: 'BaseId' defines operator == or operator != but does not override Object.Equals(object o)</code><br/><br/>
  But if I implement BaseId.Equals(object o), it'll just be to call the base class implementation in Object.Equals(object o). I don't see how this will ever get called anyway; it's always overridden in the derived class, and the implementation there doesn't call up to this implementation.</p>
  </li>
  <li><p>Not overriding BaseId.GetHashCode() in DerivedId generates a compile warning:<br/><br/>
  <code>warning CS0659: 'DerivedId' overrides Object.Equals(object o) but does not override Object.GetHashCode()</code><br/><br/>
  This derived class has no additional state, so there's nothing for me to do in an implementation of DerivedId.GetHashCode(), except to call the base class implementation in BaseId.GetHashCode().<br/><br/></p>
  </li>
  </ol>
  <p>I can suppress the compiler warnings or just implement the methods and have them call the base class implementations, but I want to make sure I'm not missing something.</p>
  <p>Is there something odd about the way I did this, or is this just one of those things that you have to do to suppress warnings on otherwise correct code?</p>