tags:

views:

93

answers:

2

A class inherits from HashSet to get a set of unique objects with custom EqualKeys(T x, T y) check instead of IEqualityComparer.

public class UniqueSet<T> : HashSet<T> where T : IKey
{
    public new void Add(T item)
    {
         // .. check item for null, empty key etc.

          if (base.Any(t => UniqueSet<T>.EqualKeys(t, item)))
          {
             throw new ArgumentException(..);
          }
          if (!base.Add(item)) throw new ArgumentException(..);
     }

    private static bool EqualKeys(T x, T y) 
    {
       return ((IKey)x).Key.Equals(((IKey)y).Key, StringComparison.CurrentCultureIgnoreCase);
    }
}

The code doesn't compile because I have to replace base.Any with this.Any.
I am afraid I don't understand why that is?

+11  A: 

"Any" is an extension method, not a method of HashSet<T>. It doesn't exist on the base type, so you cannot invoke it explicitly on the base type. When you invoke it with "this.Any", the overload resolution code cannot find "Any" on the type of "this" so it starts looking for extension methods, and finds one.

Not your question, but I'll mention it anyway: why throw if you add to a set that already has such an element? Why not just make it a no-op to do so? By throwing you make it a requirement for the caller of Add to know whether the element is in the set already or not, which seems like an onerous requirement.

Eric Lippert
see also this question: http://stackoverflow.com/questions/3510964/why-is-the-this-keyword-required-to-call-an-extension-method-from-within-the-ex
M4N
I see, I didn't take note of the '(extension)' prefix in the tooltips! But then why is explicitly using the base type different from explicitly using the this type? "It" could also look for extension methods from the type of base and find one? Probably answered in the link above..
Gerard
My answer to your question: the class is more of an internal thing: developers should never ever add duplicates, that's important to know and therefore I throw. To keep it simple I do not want my objects to implement Equals, HashCode and such.
Gerard
@Gerard: When you use "base" you are waving a big red flag that says "Hey! I'm doing a non-virtual dispatch over here!" That's it's purpose: to *specifically* call a method *on the base class*. When you explicitly say that you want to call a method on the base class, we look for a method *on the base class*. Using "base" with a method that isn't on the base class is almost certainly a mistake, so we flag it as an error rather than silently allowing the mistake.
Eric Lippert
+1  A: 

Because HashSet<T> doesn't implement Any(). Any() is an Extension Method from IEnumerable<T>. When you use base, you are explicitly referencing the base type and not its extension methods.

Justin Niessner
Or is `.Any()` an Extension Method from `static class Enumerable`, cause thats where 'go to definition' ends up (or is it the same)? How does HashSet find this static class - it is in another namespace?
Gerard
@Gerard - Enumerable is the static class that defines the extension methods that operate on `IEnumerable<T>`.
Justin Niessner