CA1010: Las colecciones deben implementar la interfaz genérica

Propiedad Value
Identificador de la regla CA1010
Título Las colecciones deben implementar la interfaz genérica
Categoría Diseño
La corrección es problemática o no problemática Poco problemático
Habilitado de forma predeterminada en .NET 8 No

Causa

Un tipo implementa la interfaz System.Collections.IEnumerable, pero no implementa la interfaz System.Collections.Generic.IEnumerable<T>, y el ensamblado que lo contiene tiene como destino .NET. Esta regla ignora los tipos que implementan System.Collections.IDictionary.

De forma predeterminada, esta regla solo examina los tipos visibles externamente, pero es configurable. También puede configurar interfaces adicionales para requerir la implementación de una interfaz genérica.

Descripción de la regla

Para ampliar la utilidad de una colección, implemente una de las interfaces de colección genéricas. Entonces podrá utilizar la colección para rellenar tipos de colecciones genéricas, como las siguientes:

Cómo corregir infracciones

Para corregir una infracción de esta regla, implemente una de las interfaces de colección genéricas siguientes:

Cuándo suprimir las advertencias

Es seguro suprimir una advertencia de esta regla. Sin embargo, el uso de la colección será más limitado.

Supresión de una advertencia

Si solo quiere suprimir una única infracción, agregue directivas de preprocesador al archivo de origen para deshabilitar y volver a habilitar la regla.

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

Para deshabilitar la regla de un archivo, una carpeta o un proyecto, establezca su gravedad en none del archivo de configuración.

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

Para obtener más información, consulte Procedimiento para suprimir advertencias de análisis de código.

Configuración del código para analizar

Use las opciones siguientes para configurar en qué partes del código base se va a ejecutar esta regla.

Puede configurar estas opciones solo para esta regla, para todas las reglas a las que se aplica o para todas las reglas de esta categoría (Diseño) a las que se aplica. Para más información, vea Opciones de configuración de reglas de calidad de código.

Incluir superficies de API específicas

Puede configurar en qué partes del código base ejecutar esta regla, en función de su accesibilidad. Por ejemplo, para especificar que la regla solo se debe ejecutar en la superficie de API no públicas, agregue el siguiente par clave-valor a un archivo .editorconfig en el proyecto:

dotnet_code_quality.CAXXXX.api_surface = private, internal

Interfaces genéricas adicionales necesarias

Puede configurar la lista de nombres de interfaz (separados por |) con la interfaz genérica completa necesaria (separada por ->).

Formatos de interfaz permitidos:

  • Solo nombre de interfaz (incluye todas las interfaces con el nombre, con independencia del tipo contenedor o el espacio de nombres).
  • Nombres completos en el formato de identificador de documentación del símbolo, con un prefijo T: opcional.

Ejemplos:

Valor de la opción Resumen
dotnet_code_quality.CA1010.additional_required_generic_interfaces = ISomething->System.Collections.Generic.IEnumerable`1 Se espera que todos los tipos que implementan ISomething, con independencia de su espacio de nombres, implementen también System.Collections.Generic.IEnumerable<T>.
dotnet_code_quality.CA1010.additional_required_generic_interfaces = T:System.Collections.IDictionary->T:System.Collections.Generic.IDictionary`2 Se espera que todos los tipos que implementan System.Collections.IDictionary también implementen System.Collections.Generic.IDictionary<TKey,TValue>.

Ejemplo

En el ejemplo siguiente se muestra una clase que deriva de la clase no genérica CollectionBase e infringe esta regla.

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

Para corregir una infracción de esta regla, realice una de las siguientes acciones:

Corrección mediante la implementación de interfaces

En el ejemplo siguiente se corrige la infracción mediante la implementación de estas interfaces genéricas: IEnumerable<T>, ICollection<T> y 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()
        {
        }
    }
}

Corrección mediante el cambio de clase base

En el ejemplo siguiente se corrige la infracción cambiando la clase base de la colección de la clase CollectionBase no genérica a la clase Collection<T> genérica (Collection(Of T) en Visual Basic).

public class Book
{
    public Book()
    {
    }
}

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

El cambio de la clase base de una clase que ya se ha lanzado se considera un cambio importante para los consumidores existentes.

Vea también