返回IEnumerable并作为参数传递

时间:2014-10-19 23:25:22

标签: c# coding-style ienumerable ilist function-calls

我读了很多关于为什么返回IEnumerable而不是IList(或类似的东西)更好的原因。但现在我陷入了困境。

考虑这样的事情:我有一些函数可以执行多个枚举,因此将IReadOnlyCollection作为参数,创建一个新的List并将其作为IEnumerable返回。

IEnumerable<int> Foo1(IReadOnlyCollection<int> bar)
{
   bar.Any();
   bar.First();
   return new List<int>() {1, 2, 3};
}
IEnumerable<int> Foo2(IReadOnlyCollection<int> bar)
{
   bar.Any();
   bar.First();
   return new List<int>() {1, 2, 3};
}
IEnumerable Foo3 ...

现在,如果我想一个接一个地打电话给我,我必须做这样的事情

var tmp = Foo1(new List<int>() {1, 2, 3});
tmp = Foo2(tmp.ToList());
tmp = Foo3(tmp.ToList());
tmp = Foo4(tmp.ToList());
tmp = Foo5(tmp.ToList());

这意味着我必须创建一个11个列表。第一个,每个函数一个,每个函数调用一个。但事实上,创建6个列表就足够了。 有没有更好的方法,或者在返回IEnumerable时这只是一个可能的缺点?

1 个答案:

答案 0 :(得分:2)

一般来说,这只是返回IEnumerable时固有的权衡。

返回IEnumerable的优点是你可以改变你的Foo()实现来返回几乎任何类型的集合(甚至是带有yield return或LINQ的惰性序列),而无需更改API。在创建界面时,平衡这一优势非常重要,因为IEnumerable API的消费者想要多次枚举它总是必须将其转换为集合。

更一般地说,返回更具体的类型(例如List over IList)对消费者最有用,而且在维护API方面最具挑战性。有些事情需要考虑:

  • 是否有任何真实的用例来返回延迟评估的序列?如果没有,消费者可能会喜欢获得一个集合类型而不是IEnumerable
  • 结果集的此顺序是否重要?在这种情况下,List,IList或IReadOnlyList通常比ICollection或IReadOnlyCollection等更好?
  • 保证返回的集合是新生成的还是可以缓存/查看内部数据?如果是后者?如果您将来可以看到转换为后一种模式,那么您将确保返回只读接口或集合类型。

如果您只是担心创建新列表的性能(几乎在所有情况下都不应该成为真正的问题),您可以随时创建扩展名:

public static IReadOnlyCollection<T> AsReadOnlyCollection<T>(this IEnumerable<T> @this)
{
    return @this as IReadOnlyCollection<T> ?? @this.ToArray();
}