C# Collection<T> 与 List<T> 你应该在你的接口上使用什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/271710/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 21:01:45  来源:igfitidea点击:

Collection<T> versus List<T> what should you use on your interfaces?

c#.netcollectionscode-analysis

提问by bovium

The code looks like below:

代码如下所示:

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

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

When I Run Code Analysis i get the following recommendation.

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

Warning 3 CA1002 : Microsoft.Design : Change 'List' in 'IMyClass.GetList()' to use Collection, ReadOnlyCollection or KeyedCollection

警告 3 CA1002:Microsoft.Design:将“IMyClass.GetList()”中的“List”更改为使用 Collection、ReadOnlyCollection 或 KeyedCollection

How should I fix this and what is good practice here?

我应该如何解决这个问题,这里有什么好的做法?

采纳答案by Greg Beech

To answer the "why" part of the question as to why not List<T>, The reasons are future-proofing and API simplicity.

要回答为什么不这个问题的“为什么”部分List<T>,原因是面向未来和 API 简单。

Future-proofing

面向未来

List<T>is not designed to be easily extensible by subclassing it; it is designed to be fast for internal implementations. You'll notice the methods on it are not virtual and so cannot be overridden, and there are no hooks into its Add/Insert/Removeoperations.

List<T>不能通过子类化来轻松扩展;它旨在为内部实现快速。你会发现它的方法不是虚拟的,因此不能被覆盖,并且没有钩到其Add/ Insert/Remove操作。

This means that if you need to alter the behavior of the collection in the future (e.g. to reject null objects that people try to add, or to perform additional work when this happens such as updating your class state) then you need to change the type of collection you return to one you can subclass, which will be a breaking interface change (of course changing the semantics of things like not allowing null may also be an interface change, but things like updating your internal class state would not be).

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

So by returning either a class that can be easily subclassed such as Collection<T>or an interface such as IList<T>, ICollection<T>or IEnumerable<T>you can change your internal implementation to be a different collection type to meet your needs, without breaking the code of consumers because it can still be returned as the type they are expecting.

因此,通过返回,要么可以很容易的子类,如类Collection<T>或接口,例如IList<T>ICollection<T>或者IEnumerable<T>你可以改变你的内部实现是一个不同的集合类型,以满足您的需求,而不破坏消费者的代码,因为它仍然可以为返回他们期待的类型。

API Simplicity

API 简单性

List<T>contains a lot of useful operations such as BinarySearch, Sortand so on. However if this is a collection you are exposing then it is likely that you control the semantics of the list, and not the consumers. So while your class internally may need these operations it is very unlikely that consumers of your class would want to (or even should) call them.

List<T>包含很多有用的操作,例如BinarySearchSort等等。但是,如果这是您要公开的集合,那么您可能会控制列表的语义,而不是消费者。因此,虽然您的类在内部可能需要这些操作,但您的类的使用者不太可能想要(甚至应该)调用它们。

As such, by offering a simpler collection class or interface, you reduce the number of members that users of your API see, and make it easier for them to use.

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

回答by Jon Skeet

I would personally declare it to return an interface rather than a concrete collection. If you really want list access, use IList<T>. Otherwise, consider ICollection<T>and IEnumerable<T>.

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

回答by Tamas Czinege

Well the Collection class is really just a wrapper class around other collections to hide their implementation details and other features. I reckon this has something to do with the property hiding coding pattern in object-oriented languages.

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

I think you shouldn't worry about it, but if you really want to please the code analysis tool, just do the following:

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

//using System.Collections.ObjectModel;

Collection<MyClass> myCollection = new Collection<MyClass>(myList);

回答by Timothy Khouri

I don't think anyone has answered the "why" part yet... so here goes. The reason "why" you "should" use a Collection<T>instead of a List<T>is because if you expose a List<T>, then anyone who gets access to your object can modify the items in the list. Whereas Collection<T>is supposed to indicate that you are making your own "Add", "Remove", etc methods.

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

You likely don't need to worry about it, because you're probably coding the interface for yourself only (or maybe a few collegues). Here's another example that might make sense.

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

If you have a public array, ex:

如果您有一个公共数组,例如:

public int[] MyIntegers { get; }

You would think that because there is only a "get" accessor that no-one can mess with the values, but that's not true. Anyone can change the values inside there just like this:

您可能会认为,因为只有一个“get”访问器,没有人可以弄乱这些值,但事实并非如此。任何人都可以像这样更改里面的值:

someObject.MyIngegers[3] = 12345;

Personally, I would just use List<T>in most cases. But if you are designing a class library that you are going to give out to random developers, and you need to rely on the state of the objects... then you'll want to make your own Collection and lock it down from there :)

就个人而言,我只会List<T>在大多数情况下使用。但是,如果您正在设计一个将分发给随机开发人员的类库,并且您需要依赖对象的状态……那么您将需要创建自己的集合并从那里将其锁定: )

回答by chakrit

It's mostly about abstracting your own implementations away instead of exposing the List object to be manipulated directly.

它主要是关于抽象您自己的实现,而不是公开要直接操作的 List 对象。

It's not good practice to let other objects (or people) modify the state of your objects directly. Think property getters/setters.

让其他对象(或人)直接修改您对象的状态并不是一个好习惯。想想属性 getter/setter。

Collection -> For normal collection
ReadOnlyCollection -> For collections that shouldn't be modified
KeyedCollection -> When you want dictionaries instead.

Collection -> 对于普通集合
ReadOnlyCollection -> 对于不应修改的集合
KeyedCollection -> 当你想要字典时。

How to fix it depends on what you want your class to do and the purpose of the GetList() method. Can you elaborate?

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

回答by Harald Scheirich

In these kind of case I usually try to expose the least amount of implemententation that is needed. If the consumers do not need to know that you are actually using a list then you don't need to return a list. By returning as Microsoft suggests a Collection you hide the fact that you are using a list from the consumers of your class and isolate them against an internal change.

在这种情况下,我通常会尝试公开所需的最少实现。如果消费者不需要知道您实际上在使用一个列表,那么您就不需要返回一个列表。通过返回 Microsoft 建议的集合,您可以向类的使用者隐藏您正在使用列表的事实,并将它们与内部更改隔离开来。

回答by Konstantin Isaev

I don't see any problem with returning something like

我认为返回类似的东西没有任何问题

this.InternalData.Filter(crteria).ToList();

If I returned a disconnected copyof internal data, or detached result of a data query - I can safely return List<TItem>without exposing any of implementation details, and allow to use the returned data in the convenient way.

如果我返回内部数据的断开连接 副本,或数据查询的分离结果 - 我可以安全地返回List<TItem>而不暴露任何实现细节,并允许以方便的方式使用返回的数据。

But this depends on what type of consumer I expect - if this is a something like data grid I prefer to return IEnumerable<TItem>which will be the copied list of itemsanyway in most cases :)

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

回答by NullReference

Something to add though it's been a long time since this was asked.

虽然自从被问到这个问题已经很长时间了,但还是要补充一些。

When your list type derives from List<T>instead of Collection<T>, you cannot implement the protected virtual methods that Collection<T>implements. What this means is that you derived type cannot respond in case any modifications are made to the list. This is because List<T>assumes you are aware when you add or remove items. Being able to response to notifications is an overhead and hence List<T>doesn't offer it.

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

In cases when external code has access to your collection, you may not be in control of when an item is being added or removed. Therefore Collection<T>provides a way to know when your list was modified.

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