返回值数组的最佳实践 (.NET)

3
通常我的方法如下所示:
public List<int> Method1(int input)
{
    var output = new List<int>();
    //add some items to output
    return output;
}

但是FxCop建议使用另一种IList实现而不是List,但我记不清是哪种了。备选方案包括将其作为IList、ICollection或IEnumerable返回以获得更大的灵活性,或者使用完全不同的方式,如下面的代码。
public int[] Method2(int input)
{
    var output = new List<int>();
    //add some items to output
    return output.ToArray();
}

在所有的选择、提供和可能性中,哪一种被认为是最佳实践?
9个回答

6

除非您特别需要列表,否则应返回IEnumerable / IEnumerable <T>,然后您应该返回IList <T>


我同意,但你能详细说明一下为什么吗? - mmcdole
因为它允许您在需要时更改函数内部的实现细节,而不会破坏调用该函数的代码。 - Joel Coehoorn
例如,也许现在你实际上返回一个数组,但是在将来的某个时候,你更新代码以返回一个List<T>。如果你承诺的只是返回IEnumerable<T>,那么调用代码仍然可以正常工作。 - Joel Coehoorn

5
在“Framework Design Guidelines”(第二版)的§8.3.1中,有很多关于集合作为返回值的内容,总结如下:
  • 不要提供可设置的集合属性。
  • 应该使用Collection<T>Collection<T>的子类来表示可读/写集合的属性或返回值。
  • 应该使用ReadOnlyCollection<T>ReadOnlyCollection<T>的子类或在极少数情况下使用IEnumerable<T>来表示只读集合的属性或返回值。

(还有更多内容,但这三个是核心内容)。

上述内容中的第一个:除非您希望用户能够更改它(然后可能需要自定义类型以便您有一定程度的控制),否则不要返回对内部集合的引用。

我会返回IList<T>并确保我没有定义实际返回的类型,除非我返回一个迭代器(那么我会使用IEnumerable<T>)。


5
Eric Lippert在他的一篇好文章中解释了为什么返回数组通常是不好的想法
通常情况下,您应该尽可能地通用,而不会给调用方法的人带来过多的麻烦。优先选择接口而不是具体类,并选择最通用的接口。
返回接口更好地封装了您的实现,并将使未来的更改变得更容易。如果您从具体类型开始,就已经承诺要始终返回该类型。 IEnumerable<T>是最好的起点。随着LINQ的出现,只要有一个枚举,调用者几乎可以轻松地完成所有操作。如果调用者偶尔需要列表,很容易调用.ToList()
如果调用者可能需要特定的索引来访问返回的集合,或者如果他们可能希望自己修改集合(插入/删除/重新排序项),请考虑使用IList<T>

3
ReadOnlyCollection<T> 是另一个选择。

但是仅当您不想让调用者更新列表时才这样做。无论如何,对您的答案加1。 - Leandro López

2

返回调用此方法的代码中需要的接口。

如果您需要对结果执行列表操作,请返回IList<T>。 如果您只需要枚举结果,请返回IEnumerable<T>

实际上,这些是我最常用的。 除非有非常好的理由,否则我从公共接口中不返回数组。


1

这取决于情况。

你想让调用者能够修改项目并且你能够看到这些更改吗?数组可以被修改。IList接口定义了修改方法(但实现可能不允许)。

你能详细说明一下FxCop警告吗?

肯特


FxCop建议您返回ReadOnlyCollection而不是List。 - Jader Dias
那似乎有些奇怪。就像我说的,如果你真的希望调用者能够修改内容怎么办? - Kent Boogaart
不要在对象模型中公开List<T>。请改用Collection<T>、ReadOnlyCollection<T>或KeyedCollection<K,V>。 List<T>的使用应限于实现,而不是对象模型API。List<T>针对性能进行了优化,但牺牲了长期版本控制的能力。... - Jader Dias
例如,如果您将List<T>返回给客户端代码,则永远无法在客户端代码修改集合时接收到通知。 - Jader Dias
这是CA1002 DoNotExposeGenericLists(设计规则)中的内容。帮助:http://msdn2.microsoft.com/ms182142(VS.90).aspx - Jader Dias

1

这取决于您的需求。总的来说,通过强类型数组进行迭代是所有集合类型中最快的。如果您不需要调整大小/添加/搜索它们,那么数组就非常好用。


1

我几乎总是使用 List,因为它提供了我经常发现最有用的方法。

返回一个 IEnumerable 的一个潜在负面后果是,任何在枚举时抛出的异常都来自于离实际构建对象的代码区域相当远的地方,这使得错误跟踪更加困难。


列表在 LINQ 之前很方便用于像“查找”这样的操作,但是在 3.5 之后,它不会提供任何标准 IEnumerable 扩展方法所不能得到的东西。 - AwesomeTown

0

一些指数或多项式算法中有很多内部值需要提取,而不需要添加多个返回这些单独值的重复方法。相反,只需返回新的 int[] { log n, x^n, residue }。

您可以创建多个外观方法;但您只需要一个算法来完成工作。最好它不是递归的。


目前你的回答不够清晰,请编辑并添加更多细节,以帮助其他人理解它如何回答问题。你可以在帮助中心找到有关如何编写好答案的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接