[英]What is the best practice to return List of data from public api inside class library?
I have a class library which contains a method returning List to the clients (mvc,console app etc...).我有一个类库,其中包含一个将 List 返回给客户端(mvc、控制台应用程序等)的方法。
Now while I was reading Guidelines for Collections , I came to know about below point:现在,当我阅读《收藏指南》时,我了解到以下几点:
X DO NOT use ArrayList or
List<T>
in public APIs.X 不要在公共 API 中使用 ArrayList 或
List<T>
。
Currently the client which is consuming my class library api is MVC which just loops on it and perform some string.format on some properties from List<Statistics>
but do not change anything on original list.目前,使用我的类库 api 的客户端是 MVC,它只是循环它并对
List<Statistics>
某些属性执行一些 string.format,但不更改原始列表中的任何内容。
I have thought of considering IEnumerable<Statistics>
but then client can also cast it to List and then manipulate it and same goes with IReadOnlyList also.我曾考虑考虑
IEnumerable<Statistics>
但客户端也可以将其转换为 List 然后对其进行操作,IReadOnlyList 也是如此。
MSDN design guidelines does not state that if not ArrayList
or List<T>
then what should be the appropriate COLLECTION for return List of something for public API? MSDN 设计指南没有说明如果不是
ArrayList
或List<T>
那么什么应该是适当的 COLLECTION 来返回公共 API 的某些东西的列表?
This is my base class which is exposed to client :这是我暴露给客户端的基类:
public abstract class BaseManager
{
//Other shared code
public abstract List<Statistics> GetStatistics();
}
public class Manager1 : BaseManager
{
public override List<Statistics> GetStatistics()
{
var stats = new List<Statistics>();
stats.Add(new Statistics { .... });
stats.Add(new Statistics { .... });
stats.Add(new Statistics { .... });
stats.Add(new Statistics { .... });
return stats;
}
}
As a rule of thumb, you want to expose to your clients as little as possible.根据经验,您希望尽可能少地向客户展示。
You also don't want to tie them to a specific implementation if you have an interface that guarantees the contract you allow them.如果您有一个接口来保证您允许它们的合同,您也不希望将它们与特定的实现联系起来。
So, in this spirit -所以,本着这种精神——
If you want your client to only be able to read the data returned using a foreach
loop, then return an IEnumerable<T>
.如果您希望您的客户端只能读取使用
foreach
循环返回的数据,则返回IEnumerable<T>
。
If you want your clients to have access to the count
property, return an IReadOnlyCollection<T>
.如果您希望您的客户能够访问
count
属性,请返回IReadOnlyCollection<T>
。
If you want your client to be able to access a specific part of the data based on it's index, than return an IReadOnlyList<T>
.如果您希望您的客户端能够根据其索引访问数据的特定部分,则返回
IReadOnlyList<T>
。
Please note that IReadOnlyList<T>
inherits the IReadOnlyCollection<T>
and this interface inherits the IEnumerable<T>
- so all of these options will allow the usage of foreach
, the last two will allow the usage of count
(as a property), and the last one will allow the usage of an indexer.请注意
IReadOnlyList<T>
继承了IReadOnlyCollection<T>
并且这个接口继承了IEnumerable<T>
- 所以所有这些选项都将允许使用foreach
,最后两个将允许使用count
(作为属性),最后一个将允许使用索引器。
Also, please note that your underlying type can still be a List
as it implements the IReadOnlyList<T>
and therefor all other interfaces I've mentioned.另外,请注意,您的基础类型仍然可以是
List
因为它实现了IReadOnlyList<T>
以及我提到的所有其他接口。
Another thing to keep in mind is that the ReadOnly
in this case does not mean that all the members held by the collection are immutable - you can still change the properties of them (assuming they are mutable types) - but the collection itself being immutable - you can't add or remove items to / from it.要记住的另一件事是,在这种情况下
ReadOnly
并不意味着集合所拥有的所有成员都是不可变的 - 您仍然可以更改它们的属性(假设它们是可变类型) - 但集合本身是不可变的 -您不能在其中添加或删除项目。
Update更新
Following your comment:按照您的评论:
If the IEnumerable<T>
is a list you can down-cast it:如果
IEnumerable<T>
是一个列表,您可以向下转换它:
IEnumerable<int> myIEnum = new List<int>();
var myList = (List<int>)myIEnum;
But the ToList()
extension method only creates a list that is a copy of the original IEnumerable<T>
.但是
ToList()
扩展方法只创建一个列表,它是原始IEnumerable<T>
的副本。
If your base class would be:如果您的基类是:
public abstract class BaseManager
{
//Other shared code
public abstract IEnumerable<Statistics> GetStatistics();
}
The derived classes can still use a list inside the method, but will return it as an IEnumerable<Statistics>
:派生类仍然可以在方法内部使用列表,但会将其作为
IEnumerable<Statistics>
:
public class Manager1 : BaseManager
{
public override IEnumerable<Statistics> GetStatistics()
{
var stats = new List<Statistics>();
stats.Add(new Statistics { .... });
stats.Add(new Statistics { .... });
stats.Add(new Statistics { .... });
stats.Add(new Statistics { .... });
return stats;
}
}
If you want to actually create an IEnumerable
that can't be down-cast to a list you can always do this:如果您想实际创建一个不能向下转换为列表的
IEnumerable
,您可以随时执行以下操作:
public override IEnumerable<Statistics> GetStatistics()
{
var stats = new List<Statistics>();
stats.Add(new Statistics { .... });
stats.Add(new Statistics { .... });
stats.Add(new Statistics { .... });
stats.Add(new Statistics { .... });
foreach(var stat in stats)
{
yield return stat;
}
}
If you are familiar with .Net, you may notice there are a lot class with the name of _______Collection
.如果您熟悉 .Net,您可能会注意到有很多名为
_______Collection
。 They match the conditions in the article, so I think they are what the guideline recommends.它们符合文章中的条件,所以我认为它们是指南推荐的。
Such as:如:
So what they suggest are所以他们建议的是
StatisticsCollection
StatisticsCollection
ICollection<Statistics>
ICollection<Statistics>
这样的集合接口
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.