CA1010 : Les collections doivent implémenter une interface générique

Propriété Value
Identificateur de la règle CA1010
Titre Les collections doivent implémenter une interface générique
Catégorie Conception
Le correctif est cassant ou non cassant Sans rupture
Activé par défaut dans .NET 8 Non

Cause

Un type implémente l’interface System.Collections.IEnumerable, mais n’implémente pas l’interface System.Collections.Generic.IEnumerable<T>, et l’assembly contenant cible .NET. Cette règle ignore les types qui implémentent System.Collections.IDictionary.

Par défaut, cette règle examine uniquement les types visibles en externe, mais elle est configurable. Vous pouvez également configurer des interfaces supplémentaires pour exiger l’implémentation d’une interface générique.

Description de la règle

Pour étendre la facilité d’utilisation d’une collection, implémentez l’une des interfaces de collection génériques. Ensuite, la collection peut être utilisée pour remplir des types de collection génériques, comme suit :

Comment corriger les violations

Pour corriger une violation de cette règle, implémentez l’une des interfaces de collection génériques suivantes :

Quand supprimer les avertissements

Il est sûr de supprimer un avertissement de cette règle; toutefois, l’utilisation de la collection sera plus limitée.

Supprimer un avertissement

Si vous voulez supprimer une seule violation, ajoutez des directives de préprocesseur à votre fichier source pour désactiver et réactiver la règle.

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

Pour désactiver la règle sur un fichier, un dossier ou un projet, définissez sa gravité sur none dans le fichier de configuration.

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

Pour plus d’informations, consultez Comment supprimer les avertissements de l’analyse de code.

Configurer le code à analyser

Utilisez l’option suivante pour configurer les parties de votre codebase sur lesquelles exécuter cette règle.

Vous pouvez configurer ces options pour cette règle uniquement, pour toutes les règles auxquelles elles s’appliquent ou pour toutes les règles de cette catégorie (Conception) auxquelles elles s’appliquent. Pour plus d’informations, consultez Options de configuration des règles de qualité du code.

Inclure des surfaces d’API spécifiques

Vous pouvez configurer les parties de votre codebase sur lesquelles exécuter cette règle, en fonction de leur accessibilité. Par exemple, pour spécifier que la règle doit s’exécuter uniquement sur la surface d’API non publique, ajoutez la paire clé-valeur suivante à un fichier .editorconfig dans votre projet :

dotnet_code_quality.CAXXXX.api_surface = private, internal

Interfaces génériques supplémentaires requises

Vous pouvez configurer la liste des noms d’interface (séparés par |) avec leur interface complète générique requise (séparée par ->).

Formats d’interface autorisés :

  • Nom de l’interface uniquement (inclut toutes les interfaces portant le nom, quel que soit le type ou l’espace de noms contenant).
  • Les noms complets au format d’ID de documentation du symbole, avec un préfixe T: facultatif.

Exemples :

Valeur d'option Récapitulatif
dotnet_code_quality.CA1010.additional_required_generic_interfaces = ISomething->System.Collections.Generic.IEnumerable`1 Tous les types qui implémentent ISomething indépendamment de son espace de noms doivent également implémenter System.Collections.Generic.IEnumerable<T>.
dotnet_code_quality.CA1010.additional_required_generic_interfaces = T:System.Collections.IDictionary->T:System.Collections.Generic.IDictionary`2 Tous les types qui implémentent System.Collections.IDictionary sont censés également implémenter System.Collections.Generic.IDictionary<TKey,TValue>.

Exemple

L’exemple suivant montre une classe qui dérive de la classe non générique CollectionBase et enfreint cette règle.

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

Pour corriger une infraction à cette règle, effectuez l’une des opérations suivantes :

Corriger par implémentation de l’interface

L’exemple suivant corrige la violation en implémentant ces interfaces génériques : IEnumerable<T>, ICollection<T> et 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()
        {
        }
    }
}

Correction par changement de classe de base

L’exemple suivant corrige la violation en changeant la classe de base de la collection de la classe non générique CollectionBase en classe générique Collection<T> (Collection(Of T) en Visual Basic).

public class Book
{
    public Book()
    {
    }
}

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

La modification de la classe de base d’une classe déjà publiée est considérée comme un changement cassant pour les consommateurs existants.

Voir aussi