CA1010: коллекции должны реализовывать универсальный интерфейс
Свойство | Значение |
---|---|
Идентификатор правила | CA1010 |
Заголовок | Коллекции должны реализовать универсальный интерфейс |
Категория | Проектирование |
Исправление является критическим или не критическим | Не критическое |
Включен по умолчанию в .NET 8 | No |
Причина
Тип реализует интерфейс System.Collections.IEnumerable, но не реализует интерфейс System.Collections.Generic.IEnumerable<T>, а включающая его сборка предназначена для .NET. Это правило игнорирует типы, реализующие System.Collections.IDictionary.
По умолчанию это правило проверяет только видимые извне типы, но это поведение можно настроить. Кроме того, можно настроить дополнительные интерфейсы, чтобы они требовали реализацию универсального интерфейса.
Описание правила
Чтобы расширить возможности использования коллекции, реализуйте один из универсальных интерфейсов коллекции. Затем данную коллекцию можно использовать для заполнения универсальных типов коллекции, таких как следующие:
- System.Collections.Generic.List<T>
- System.Collections.Generic.Queue<T>
- System.Collections.Generic.Stack<T>
Устранение нарушений
Чтобы устранить нарушение этого правила, реализуйте один из следующих универсальных интерфейсов коллекции:
- System.Collections.Generic.IEnumerable<T>
- System.Collections.Generic.ICollection<T>
- System.Collections.Generic.IList<T>
Когда лучше отключить предупреждения
Можно спокойно скрыть предупреждения для этого правила, но использование коллекции будет ограничено.
Отключение предупреждений
Если вы просто хотите отключить одно нарушение, добавьте директивы препроцессора в исходный файл, чтобы отключить и повторно включить правило.
#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);
}
}
Чтобы устранить нарушение этого правила, выполните одно из следующих действий:
- Реализуйте универсальный интерфейс.
- Измените базовый класс на тип, который уже реализует универсальные и неуниверсальные интерфейсы, такой как класс
Collection<T>
.
Исправление с помощью реализации интерфейсов
В примере ниже нарушение устраняется путем реализации следующих универсальных интерфейсов: 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()
{
}
}
Изменение базового класса уже выпущенного класса считается критическим изменением для существующих потребителей.
Связанные правила
- CA1005: не используйте слишком много параметров в универсальных типах
- CA1000: не объявляйте статические элементы в универсальных типах
- CA1002: не следует раскрывать универсальные списки
- CA1003: используйте экземпляры обработчика универсальных событий