CA1010:集合应实现泛型接口

属性
规则 ID CA1010
标题 集合应实现泛型接口
类别 设计
修复是中断修复还是非中断修复 非中断
在 .NET 8 中默认启用

原因

类型实现 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

其他所需的泛型接口

你可以配置接口名称列表(用 | 进行分隔)及其所需的通用完全限定接口(用 -> 进行分隔)。

允许的接口格式:

  • 仅接口名称(包括具有相应名称的所有接口,不考虑包含的类型或命名空间)。
  • 完全限定的名称,使用符号的文档 ID 格式,前缀为 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>(在 Visual Basic 为 Collection(Of T))类来解决冲突。

public class Book
{
    public Book()
    {
    }
}

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

更改已发布的类的基类,这是对现有使用者的突破性更改。

另请参阅