C# 从类库中的公共api返回数据列表的最佳实践是什么?

C# 从类库中的公共api返回数据列表的最佳实践是什么?,c#,C#,我有一个类库,其中包含一个向客户端(mvc、控制台应用程序等)返回列表的方法 现在,当我阅读时,我了解了以下几点: 不要在公共API中使用ArrayList或List 目前,使用我的类库api的客户机是MVC,它只是在其上循环,并对List中的某些属性执行string.format,但不更改原始列表中的任何内容 我曾考虑过IEnumerable,但客户端也可以将其强制转换为列表,然后对其进行操作,IReadOnlyList也是如此 MSDN设计指南没有规定,如果不是ArrayList或List,

我有一个类库,其中包含一个向客户端(mvc、控制台应用程序等)返回列表的方法

现在,当我阅读时,我了解了以下几点:

不要在公共API中使用ArrayList或
List

目前,使用我的类库api的客户机是MVC,它只是在其上循环,并对
List
中的某些属性执行string.format,但不更改原始列表中的任何内容

我曾考虑过
IEnumerable
,但客户端也可以将其强制转换为列表,然后对其进行操作,IReadOnlyList也是如此

MSDN设计指南没有规定,如果不是
ArrayList
List
,那么什么才是公共API返回列表的合适集合

这是我向客户机公开的基类:

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;
    }
}
公共抽象类BaseManager
{
//其他共享代码
公共摘要列表GetStatistics();
}
公共类管理器1:BaseManager
{
公共覆盖列表GetStatistics()
{
var stats=新列表();
添加(新的统计数据{….});
添加(新的统计数据{….});
添加(新的统计数据{….});
添加(新的统计数据{….});
返回统计;
}
}

根据经验,您希望尽可能少地向客户公开信息。
如果您有一个接口可以保证您所允许的契约,那么您也不希望将它们绑定到特定的实现

因此,本着这种精神—

如果希望客户端只能读取使用
foreach
循环返回的数据,则返回一个。
如果希望您的客户端能够访问
count
属性,请返回一个。
如果您希望您的客户机能够基于其索引访问数据的特定部分,则返回一个

请注意,
IReadOnlyList
继承
IReadOnlyCollection
,此接口继承
IEnumerable
-因此所有这些选项都将允许使用
foreach
,最后两个选项将允许使用
count
(作为属性),最后一个将允许使用索引器

另外,请注意,您的底层类型仍然可以是
列表
,因为它实现了
IReadOnlyList
以及我提到的所有其他接口

另一件需要记住的事情是,在这种情况下,
只读
并不意味着集合持有的所有成员都是不可变的-您仍然可以更改它们的属性(假设它们是可变类型)-但是集合本身是不可变的-您不能向其中添加或从中删除项

更新
您的评论如下:
如果
IEnumerable
是一个列表,您可以向下转换它:

IEnumerable<int> myIEnum = new List<int>(); 
var myList = (List<int>)myIEnum; 
派生类仍然可以在方法内使用列表,但将以
IEnumerable
的形式返回该列表:


如果您熟悉.Net,您可能会注意到有许多名为
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu.Collection
的类。它们符合文章中的条件,因此我认为它们是指南建议的

例如:

  • System.Collections.Specialized.NameValueCollection
  • System.Text.RegularExpressions.MatchCollection
  • System.Collections.Generic.Dictionary.KeyCollection
所以他们的建议是

  • 创建一个类似于统计收集的
  • 实现一个收集接口,如
    ICollection

指南解释了在何种情况下不应依赖/使用API中的列表。如果您的特定场景不是这样或类似的场景-也就是说,被调用方可以操纵返回的列表,而API实现不关心-则返回列表没有问题。但是,如果您的API依赖于被调用方的善意而不操纵列表,那么您的API有一个问题/弱点,您应该返回一个不可修改的只读集合/列表。@elgonzo统计数据仅由我的类库方法准备,显然我不希望客户机操纵统计数据。他们应该只能读取它,其他什么都不能。他们不返回列表。返回不可修改的只读集合/列表。不要让你的API依赖于调用方的善意/正确行为,因为它可以强制执行正确的行为…@elgonzo我已经更新了我的问题“我如何返回列表”,那么你能告诉我如何返回只读集合吗?客户端可以只读,但他们不能强制转换该集合以对其进行操作?实际上有一个
ReadOnlyCollection
。只需查看文档:(这不是框架/核心库提供的唯一只读集合类型;还有一些是针对特定应用场景的)但正如我在问题中提到的,如果我将返回IEnumerable,那么客户端仍然可以将其强制转换为List并对其进行操作。我已经更新了我的问题“如何返回List”您还可以创建一个List,然后使用
.AsEnumerable()
扩展方法。@EluciusFTW您可以,但它不会有帮助。您还可以看到Enumerable.cs的属性,并看到
AsEnumerable
只返回它得到的同一个对象-它接受
IEnumerable
,并在需要时返回
IEnumerable
-向上转换。那么您是说Statistics类应该实现这样的ICollection接口:public class Statistics:ICollection?统计收集类实现ICollection接口但在这种情况下,我必须实现ICollection接口的所有成员,对吗?是的。如果您认为大多数成员未被使用,请选择其他接口。“公共API”一词在
public abstract class BaseManager
{
    //Other shared code
    public abstract IEnumerable<Statistics> GetStatistics();
}
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;
    }
}
    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;
        }
    }