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

Свойство Значение
Идентификатор правила CA1010
Заголовок Коллекции должны реализовать универсальный интерфейс
Категория Проектирование
Исправление является критическим или не критическим Не критическое
Включен по умолчанию в .NET 8 No

Причина

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

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

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

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

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

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

Когда лучше отключить предупреждения

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

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

Если вы просто хотите отключить одно нарушение, добавьте директивы препроцессора в исходный файл, чтобы отключить и повторно включить правило.

#pragma warning disable CA1010
// The code that's violating the rule is on this line.
#pragma warning restore CA1010

Чтобы отключить правило для файла, папки или проекта, задайте его серьезность none в файле конфигурации.

[*.{cs,vb}]
dotnet_diagnostic.CA1010.severity = none

Дополнительные сведения см. в разделе Практическое руководство. Скрытие предупреждений анализа кода.

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

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

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

Включение определенных контактных зон 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 => (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()
    {
    }
}

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

См. также