При использовании base.Any (..) появляется предупреждение: «HashSet» не содержит определения для «Any»

Класс наследуется от HashSet, чтобы получить набор уникальных объектов с пользовательской проверкой EqualKeys(T x, T y) вместо 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);
    }
}

Код не компилируется, потому что мне нужно заменить base.Any на this.Any.
Боюсь, я не понимаю, почему?


person Gerard    schedule 01.10.2010    source источник


Ответы (2)


«Любой» - это метод расширения, а не метод HashSet<T>. Его не существует в базовом типе, поэтому вы не можете явно вызвать его в базовом типе. Когда вы вызываете его с помощью «this.Any», код разрешения перегрузки не может найти «Any» для типа «this», поэтому он начинает поиск методов расширения и находит их.

Не ваш вопрос, но я все равно об этом скажу: зачем throw, если вы добавляете в набор, в котором уже есть такой элемент? Почему бы просто не запретить это делать? Выбрасывая, вы заставляете вызывающего объекта Add знать, находится ли элемент уже в наборе или нет, что кажется обременительным требованием.

person Eric Lippert    schedule 01.10.2010
comment
см. также этот вопрос: stackoverflow.com/questions/3510964/ - person M4N; 01.10.2010
comment
Понятно, я не обратил внимание на префикс «(расширение)» во всплывающих подсказках! Но тогда почему явное использование базового типа отличается от явного использования этого типа? Можно еще поискать методы расширения по типу базы и найти тот? Наверное ответил по ссылке выше .. - person Gerard; 01.10.2010
comment
Мой ответ на ваш вопрос: класс - это скорее внутренняя вещь: разработчики никогда не должны добавлять дубликаты, это важно знать, и поэтому я бросаю. Чтобы не усложнять, я не хочу, чтобы мои объекты реализовывали Equals, HashCode и т. Д. - person Gerard; 01.10.2010
comment
@Gerard: Когда вы используете базу, вы размахиваете большим красным флагом с надписью "Эй!" Я здесь делаю невиртуальную рассылку! Это его цель: специально вызвать метод базового класса. Когда вы явно говорите, что хотите вызвать метод базового класса, мы ищем метод в базовом классе. Использование base с методом, не входящим в базовый класс, почти наверняка является ошибкой, поэтому мы помечаем это как ошибку, а не молча допускаем ошибку. - person Eric Lippert; 01.10.2010

Потому что HashSet<T> не реализует Any(). Any() - это метод расширения от IEnumerable<T>. Когда вы используете base, вы явно ссылаетесь на базовый тип, а не на его методы расширения.

person Justin Niessner    schedule 01.10.2010
comment
Или .Any() метод расширения от static class Enumerable, потому что здесь заканчивается «перейти к определению» (или это то же самое)? Как HashSet находит этот статический класс - он находится в другом пространстве имен? - person Gerard; 01.10.2010
comment
@Gerard - Enumerable - это статический класс, определяющий методы расширения, которые работают с IEnumerable<T>. - person Justin Niessner; 01.10.2010