CA1010: Kolekcje powinny implementować interfejs generyczny

Właściwości Wartość
Identyfikator reguły CA1010
Stanowisko Kolekcje powinny implementować interfejs ogólny
Kategoria Projekt
Poprawka powodująca niezgodność lub niezgodność Niezgodność
Domyślnie włączone na platformie .NET 8 Nie.

Przyczyna

Typ implementuje interfejs, ale nie implementuje System.Collections.IEnumerable interfejsu System.Collections.Generic.IEnumerable<T> i zawiera cele zestawu platformy .NET. Ta reguła ignoruje typy, które implementują System.Collections.IDictionaryprogram .

Domyślnie ta reguła analizuje tylko typy widoczne zewnętrznie, ale można to skonfigurować. Można również skonfigurować dodatkowe interfejsy, aby wymagać zaimplementowania interfejsu ogólnego.

Opis reguły

Aby poszerzyć użyteczność kolekcji, zaimplementuj jeden z interfejsów kolekcji generycznej. Następnie można użyć kolekcji do wypełniania typów kolekcji ogólnych, takich jak:

Jak naprawić naruszenia

Aby naprawić naruszenie tej reguły, zaimplementuj jeden z następujących interfejsów kolekcji ogólnych:

Kiedy pomijać ostrzeżenia

Można bezpiecznie pominąć ostrzeżenie z tej reguły; jednak użycie kolekcji będzie bardziej ograniczone.

Pomijanie ostrzeżenia

Jeśli chcesz po prostu pominąć pojedyncze naruszenie, dodaj dyrektywy preprocesora do pliku źródłowego, aby wyłączyć, a następnie ponownie włączyć regułę.

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

Aby wyłączyć regułę dla pliku, folderu lub projektu, ustaw jego ważność na none w pliku konfiguracji.

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

Aby uzyskać więcej informacji, zobacz Jak pominąć ostrzeżenia dotyczące analizy kodu.

Konfigurowanie kodu do analizowania

Użyj poniższych opcji, aby skonfigurować, które części bazy kodu mają być uruchamiane w tej regule.

Możesz skonfigurować te opcje tylko dla tej reguły, dla wszystkich reguł, do których ma ona zastosowanie, lub dla wszystkich reguł w tej kategorii (Projekt), do których ma ona zastosowanie. Aby uzyskać więcej informacji, zobacz Opcje konfiguracji reguły jakości kodu.

Uwzględnij określone powierzchnie interfejsu API

Możesz skonfigurować, na których częściach bazy kodu ma być uruchamiana ta reguła, na podstawie ich ułatwień dostępu. Aby na przykład określić, że reguła powinna być uruchamiana tylko na powierzchni niepublicznego interfejsu API, dodaj następującą parę klucz-wartość do pliku editorconfig w projekcie:

dotnet_code_quality.CAXXXX.api_surface = private, internal

Dodatkowe wymagane interfejsy ogólne

Listę nazw interfejsów (oddzielonych znakami |) można skonfigurować przy użyciu wymaganego w pełni kwalifikowanego interfejsu ogólnego (oddzielonego przez ->).

Dozwolone formaty interfejsu:

  • Tylko nazwa interfejsu (zawiera wszystkie interfejsy o nazwie, niezależnie od typu zawierającego lub przestrzeni nazw).
  • W pełni kwalifikowane nazwy w formacie identyfikatora dokumentacji symbolu z opcjonalnym T: prefiksem.

Przykłady:

Wartość opcji Podsumowanie
dotnet_code_quality.CA1010.additional_required_generic_interfaces = ISomething->System.Collections.Generic.IEnumerable`1 Oczekuje się również, że wszystkie typy, które implementują ISomethingSystem.Collections.Generic.IEnumerable<T>niezależnie od jego przestrzeni nazw.
dotnet_code_quality.CA1010.additional_required_generic_interfaces = T:System.Collections.IDictionary->T:System.Collections.Generic.IDictionary`2 Oczekuje się również, że wszystkie typy implementujące System.Collections.IDictionary usługę System.Collections.Generic.IDictionary<TKey,TValue>.

Przykład

W poniższym przykładzie przedstawiono klasę, która pochodzi z klasy niegenerycznej CollectionBase i narusza tę regułę.

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);
    }
}

Aby naprawić naruszenie tej reguły, wykonaj jedną z następujących czynności:

Poprawka implementacji interfejsu

Poniższy przykład naprawia naruszenie przez zaimplementowanie tych ogólnych interfejsów: IEnumerable<T>, ICollection<T>i 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()
        {
        }
    }
}

Poprawka po zmianie klasy bazowej

Poniższy przykład naprawia naruszenie, zmieniając klasę bazową kolekcji z klasy niegenerycznej CollectionBase na ogólną Collection<T> (Collection(Of T) w Visual Basic).

public class Book
{
    public Book()
    {
    }
}

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

Zmiana klasy bazowej już wydanej klasy jest uważana za zmianę powodującą niezgodność dla istniejących odbiorców.

Zobacz też