CA1010. Коллекции должны реализовать универсальный интерфейс

Элемент Значение
Идентификатор правила CA1010
Категория Оформление
Исправление является критическим или не критическим Не критическое

Причина

Тип реализует интерфейс System.Collections.IEnumerable, но не реализует интерфейс System.Collections.Generic.IEnumerable<T>, а включающая его сборка предназначена для .NET. Это правило игнорирует типы, реализующие System.Collections.IDictionary.

По умолчанию это правило проверяет только видимые извне типы, но это поведение можно настроить. Кроме того, можно настроить дополнительные интерфейсы, чтобы они требовали реализацию универсального интерфейса.

Описание правила

Чтобы расширить возможности использования коллекции, реализуйте один из универсальных интерфейсов коллекции. Затем данную коллекцию можно использовать для заполнения универсальных типов коллекции, таких как следующие:

Устранение нарушений

Чтобы устранить нарушение этого правила, реализуйте один из следующих универсальных интерфейсов коллекции:

Условия для отключения предупреждений

Можно спокойно скрыть предупреждения для этого правила, но использование коллекции будет ограничено.

Отключение предупреждений

Существует несколько способов скрыть предупреждения анализа кода, в том числе отключение правила для проекта, использование директивы препроцессора, чтобы отключить его для конкретной строки кода, или применение атрибута SuppressMessageAttribute. Дополнительные сведения см. в разделе Практическое руководство. Скрытие предупреждений анализа кода.

Настройка кода для анализа

Используйте следующие параметры, чтобы указать части базы кода, к которым будет применяться это правило.

Эти параметры можно настроить только для указанного правила, для всех правил или для всех правил в этой категории (разработка). Дополнительные сведения см. в статье Параметры конфигурации правила качества кода.

Включение определенных контактных зон API

Вы можете настроить, для каких частей базы кода следует выполнять это правило в зависимости от их доступности. Например, чтобы указать, что правило должно выполняться только для закрытой контактной зоны API, добавьте следующую пару "ключ-значение" в файл EDITORCONFIG в своем проекте:

dotnet_code_quality.CAXXXX.api_surface = private, internal

Дополнительные необходимые универсальные интерфейсы

Список имен интерфейсов (разделенных |) можно настроить с помощью соответствующего универсального полного интерфейса (разделенного ->).

Допустимые форматы интерфейса:

  • Только имя интерфейса (включает все интерфейсы с этим именем, в любом типе и любом пространстве имен).
  • Полные имена в формате идентификатора документации для символа с необязательным префиксом T:.

Примеры:

Значение параметра Итоги
dotnet_code_quality.CA1010.additional_required_generic_interfaces = ISomething->System.Collections.Generic.IEnumerable`1 Все типы, которые реализуют ISomething, независимо от его пространства имен, также должны реализовывать System.Collections.Generic.IEnumerable<T>.
dotnet_code_quality.CA1010.additional_required_generic_interfaces = T:System.Collections.IDictionary->T:System.Collections.Generic.IDictionary`2 Все типы, которые реализуют System.Collections.IDictionary, также должны реализовывать System.Collections.Generic.IDictionary<TKey,TValue>.

Пример

В следующем примере показан класс, производный от класса, не являющегося универсальным, CollectionBase, и нарушающий это правило.

public class Book
{
    public Book()
    {
    }
}

public class BookCollection : CollectionBase
{
    public BookCollection()
    {
    }

    public void Add(Book value)
    {
        InnerList.Add(value);
    }

    public void Remove(Book value)
    {
        InnerList.Remove(value);
    }

    public void Insert(int index, Book value)
    {
        InnerList.Insert(index, value);
    }

    public Book this[int index]
    {
        get { return (Book)InnerList[index]; }
        set { InnerList[index] = value; }
    }

    public bool Contains(Book value)
    {
        return InnerList.Contains(value);
    }

    public int IndexOf(Book value)
    {
        return InnerList.IndexOf(value);
    }

    public void CopyTo(Book[] array, int arrayIndex)
    {
        InnerList.CopyTo(array, arrayIndex);
    }
}

Чтобы устранить нарушение этого правила, выполните одно из следующих действий:

Исправление с помощью реализации интерфейсов

В примере ниже нарушение устраняется путем реализации следующих универсальных интерфейсов: IEnumerable<T>, ICollection<T> и IList<T>.

public class Book
{
    public Book()
    {
    }
}

public class BookCollection : CollectionBase, IList<Book>
{
    public BookCollection()
    {
    }

    int IList<Book>.IndexOf(Book item)
    {
        return this.List.IndexOf(item);
    }

    void IList<Book>.Insert(int location, Book item)
    {
    }

    Book IList<Book>.this[int index]
    {
        get { return (Book)this.List[index]; }
        set { }
    }

    void ICollection<Book>.Add(Book item)
    {
    }

    bool ICollection<Book>.Contains(Book item)
    {
        return true;
    }

    void ICollection<Book>.CopyTo(Book[] array, int arrayIndex)
    {
    }

    bool ICollection<Book>.IsReadOnly
    {
        get { return false; }
    }

    bool ICollection<Book>.Remove(Book item)
    {
        if (InnerList.Contains(item))
        {
            InnerList.Remove(item);
            return true;
        }
        return false;
    }

    IEnumerator<Book> IEnumerable<Book>.GetEnumerator()
    {
        return new BookCollectionEnumerator(InnerList.GetEnumerator());
    }

    private class BookCollectionEnumerator : IEnumerator<Book>
    {
        private IEnumerator _Enumerator;

        public BookCollectionEnumerator(IEnumerator enumerator)
        {
            _Enumerator = enumerator;
        }

        public Book Current
        {
            get { return (Book)_Enumerator.Current; }
        }

        object IEnumerator.Current
        {
            get { return _Enumerator.Current; }
        }

        public bool MoveNext()
        {
            return _Enumerator.MoveNext();
        }

        public void Reset()
        {
            _Enumerator.Reset();
        }

        public void Dispose()
        {
        }
    }
}

Исправление с помощью изменения базового класса

Следующий пример устраняет нарушение, изменяя базовый класс коллекции с неуниверсального класса CollectionBase на универсальный класс Collection<T> (Collection(Of T) в Visual Basic).

public class Book
{
    public Book()
    {
    }
}

public class BookCollection : Collection<Book>
{
    public BookCollection()
    {
    }
}

Изменение базового класса уже выпущенного класса считается критическим изменением для существующих потребителей.

См. также раздел