代码如下所示:

namespace Test
{
    public interface IMyClass
    {
        List<IMyClass> GetList();
    }

    public class MyClass : IMyClass
    {
        public List<IMyClass> GetList()
        {
            return new List<IMyClass>();
        }
    }
}

当我运行代码分析时,我得到以下建议。

  

警告3 CA1002:Microsoft.Design:更改'IMyClass.GetList()'中的'List'以使用Collection,ReadOnlyCollection或KeyedCollection

我该如何解决这个问题以及这里有什么好习惯?

有帮助吗?

解决方案

回答“为什么”关于为什么不 List&lt; T&gt; 的问题的一部分,原因是面向未来和API简单。

<强>面向未来

List&lt; T&gt; 的目的不是通过子类化来轻松扩展;它旨在快速进行内部实施。您会注意到它上面的方法不是虚拟的,所以不能被覆盖,并且它的添加 / 插入 / 删除没有钩子。操作。

这意味着如果您将来需要更改集合的行为(例如,拒绝人们尝试添加的空对象,或者在发生这种情况时执行其他工作,例如更新类状态),那么您需要将您返回的集合类型更改为可以子类化的集合,这将是一个破坏性的接口更改(当然,更改不允许null的事物的语义也可能是接口更改,但更新内部类状态的事情不会是)。

因此,通过返回可以轻松子类化的类(例如 Collection&lt; T&gt; )或接口(例如 IList&lt; T&gt; ), ICollection&lt; T&gt; ; IEnumerable&lt; T&gt; 您可以将内部实现更改为不同的集合类型以满足您的需求,而不会破坏消费者的代码,因为它仍然可以作为类型返回期待着。

API简洁性

List&lt; T&gt; 包含许多有用的操作,例如 BinarySearch Sort 等等。但是,如果这是您正在公开的集合,那么很可能您控制列表的语义,而不是消费者。因此,虽然您的班级内部可能需要这些操作,但您班级的消费者不太可能(甚至应该)打电话给他们。

因此,通过提供更简单的集合类或接口,您可以减少API用户看到的成员数量,并使他们更容易使用。

其他提示

我个人会声明它返回一个接口而不是一个具体的集合。如果您真的想要列表访问权限,请使用 IList&lt; T&gt; 。否则,请考虑 ICollection&lt; T&gt; IEnumerable&lt; T&gt;

主要是关于抽象你自己的实现,而不是直接暴露List对象。

让其他对象(或人)直接修改对象的状态并不是一种好习惯。想想物业的吸气者/制定者。

收藏 - &gt;对于正常的收集
ReadOnlyCollection - &gt;对于不应修改的集合
KeyedCollection - &gt;当你想要字典时。

如何修复它取决于您希望您的类做什么以及GetList()方法的目的。你能详细说明吗?

在这种情况下,我通常会尝试暴露所需的最少量的实施。如果消费者不需要知道您实际使用的是列表,则无需返回列表。通过返回,因为Microsoft建议使用Collection,您可以隐藏这样一个事实,即您正在使用类中消费者的列表,并将其与内部更改隔离开来。

我认为没有人回答“为什么”部分......所以这里。原因是“为什么”你应该“应该”使用 Collection&lt; T&gt; 而不是 List&lt; T&gt; 是因为如果您公开 List&lt; T&gt; ,那么任何有权访问的人到您的对象可以修改列表中的项目。鉴于 Collection&lt; T&gt; 应该表明您正在制作自己的“添加”,“删除”等方法。

您可能不需要担心它,因为您可能只为自己编写接口(或者可能是一些同事)。这是另一个可能有意义的例子。

如果你有一个公共阵列,例如:

public int[] MyIntegers { get; }

你会认为因为只有一个“得到”的没有人可以搞乱这些价值观的访问者,但事实并非如此。任何人都可以像这样更改其中的值:

someObject.MyIngegers[3] = 12345;

就个人而言,在大多数情况下,我只会使用 List&lt; T&gt; 。但是如果你正在设计一个你要向随机开发者提供的类库,并且你需要依赖于对象的状态......那么你将需要创建自己的Collection并从那里锁定它: )

有些东西需要补充,虽然这已经有很长一段时间了。

当您的列表类型派生自 List&lt; T&gt; 而不是 Collection&lt; T&gt; 时,您无法实现 Collection&lt; T&gt; <的受保护虚拟方法/ code> implements。 这意味着,如果对列表进行任何修改,派生类型将无法响应。这是因为 List&lt; T&gt; 假设您在添加或删除项目时知道。能够响应通知是一种开销,因此 List&lt; T&gt; 不提供它。

如果外部代码可以访问您的集合,您可能无法控制何时添加或删除项目。因此, Collection&lt; T&gt; 提供了一种了解列表修改时间的方法。

我没有看到返回类似

之类的任何问题
this.InternalData.Filter(crteria).ToList();

如果我返回了内部数据的断开副本或数据查询的分离结果 - 我可以安全地返回 List&lt; TItem&gt; ,而不会泄露任何实现细节,并允许以方便的方式使用返回的数据。

但这取决于我期望的消费者类型 - 如果这是类似于数据网格的东西我更喜欢返回 IEnumerable&lt; TItem&gt; 这将是复制的项目列表无论如何在大多数情况下:)

Collection类实际上只是围绕其他集合的包装类,以隐藏其实现细节和其他功能。我认为这与面向对象语言中的属性隐藏编码模式有关。

我认为您不应该担心,但如果您真的想取悦代码分析工具,请执行以下操作:

//using System.Collections.ObjectModel;

Collection<MyClass> myCollection = new Collection<MyClass>(myList);
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top