Collection <T>与List <T>你应该在你的界面上使用什么?
代码如下所示:
namespace Test { public interface IMyClass { List<IMyClass> GetList(); } public class MyClass : IMyClass { public List<IMyClass> GetList() { return new List<IMyClass>(); } } }
当我运行代码分析时,我得到以下build议。
警告3 CA1002:Microsoft.Design:更改“IMyClass.GetList()”中的“列表”以使用集合,ReadOnlyCollection或KeyedCollection
我应该如何解决这个问题,这里有什么好的做法?
为了回答为什么不是List<T>
的问题的“为什么”部分,原因是面向未来和API的简单性。
面向未来
List<T>
并不是通过子类化而容易扩展的; 它被devise为快速的内部实现。 你会注意到它上面的方法不是虚拟的,所以不能被覆盖,并且在它的Add
/ Insert
/ Remove
操作中没有挂钩。
这意味着,如果您需要在将来改变集合的行为(例如,拒绝人们尝试添加的空对象,或者在发生这种情况时执行其他工作,例如更新您的类状态),则需要更改types你将返回一个你可以inheritance的类,这将是一个突破的接口改变(当然,改变不允许null这样的事情的语义也可能是一个接口的改变,但更新你的内部类的状态不会)。
因此,通过返回一个可以轻松子类化的类(如Collection<T>
或一个接口(如IList<T>
, ICollection<T>
或IEnumerable<T>
,可以将您的内部实现更改为不同的集合types您的需求,而不会破坏消费者的代码,因为它仍然可以按照他们期望的types返回。
API简单
List<T>
包含了很多有用的操作,比如BinarySearch
, Sort
等等。 但是,如果这是一个你正在公开的集合,那么你很可能控制了列表的语义,而不是消费者。 所以,当你的class级内部可能需要这些操作时,class上的消费者不大可能(甚至应该)给他们打电话。
因此,通过提供更简单的集合类或接口,可以减lessAPI用户看到的成员数量,并使其更易于使用。
我会亲自声明它返回一个接口,而不是一个具体的集合。 如果你真的想要列表访问,使用IList<T>
。 否则,请考虑ICollection<T>
和IEnumerable<T>
。
这主要是关于抽象你自己的实现,而不是直接暴露List对象。
让其他对象(或人)直接修改对象的状态是不好的做法。 认为属性获得者/设置者。
collections – >用于正常collections
ReadOnlyCollection – >对于不应该被修改的集合
KeyedCollection – >当你想要字典,而不是。
如何解决它取决于你想要你的类和GetList()方法的目的。 你能详细点吗?
在这种情况下,我通常会尽量暴露出所需的最less量的实现。 如果消费者不需要知道你实际上正在使用一个列表,那么你不需要返回一个列表。 通过微软提出的一个collections集,你可以隐藏你正在使用你的类的消费者列表,并将其与内部变化隔离的事实。
我不认为有人已经回答了“为什么”的一部分了…所以这里。 “为什么”你“应该”使用一个Collection<T>
而不是List<T>
是因为如果你公开一个List<T>
,那么任何访问你的对象的人都可以修改列表中的项目。 鉴于Collection<T>
是应该表明你正在做自己的“添加”,“删除”等方法。
你可能不需要担心,因为你可能只为自己编写接口(或者也许只是一些同事)。 这是另一个可能有意义的例子。
如果你有一个公共数组,例如:
public int[] MyIntegers { get; }
你会认为,因为只有一个“得到”访问器,没有人可以混淆的价值观,但事实并非如此。 任何人都可以像这样改变里面的值:
someObject.MyIngegers[3] = 12345;
就个人而言,我会在大多数情况下使用List<T>
。 但是,如果你正在devise一个你将要发给随机开发者的类库,而且你需要依赖对象的状态……那么你就需要制作你自己的Collection并locking它: )
这个问题已经有很长时间了。
当您的列表types从List<T>
而不是Collection<T>
派生时,您无法实现Collection<T>
实现的受保护虚拟方法。 这意味着,如果对列表进行任何修改,派生types都无法响应。 这是因为List<T>
假定您添加或删除项目时您已知道。 能够响应通知是一个开销,因此List<T>
不提供它。
在外部代码访问您的collections的情况下,您可能无法控制何时添加或删除项目。 因此Collection<T>
提供了一种方法来知道你的列表何时被修改。
我没有看到任何返回类似的问题
this.InternalData.Filter(crteria).ToList();
如果我返回了内部数据的一个断开的副本 ,或者分离了一个数据查询的结果 – 我可以安全地返回List<TItem>
而不暴露任何实现细节,并允许以方便的方式使用返回的数据。
但这取决于我期望的消费者types – 如果这是一个类似于数据网格的东西,我倾向于返回IEnumerable<TItem>
,在大多数情况下,这将成为项目的复制列表 🙂
一个目的是使代码/devise更加灵活和可扩展!
那么Collection类实际上只是一个围绕其他集合的包装类来隐藏他们的实现细节和其他function。 我认为这与面向对象语言中的属性隐藏编码模式有关。
我想你不应该担心,但是如果你真的想要代码分析工具,只需要执行以下操作:
//using System.Collections.ObjectModel; Collection<MyClass> myCollection = new Collection<MyClass>(myList);