为什么让接口返回IEnumerable<T>
关于这个问题不需要过多的解释,且不是本文讨论的重点。简单来说,遵循接口最小原则,返回用户最少的行为即可。因此,能返回IEnumerable<T>则不返回List<T>或Collection<T>。
接口的实现函数如何返回IEnumerable<T>
一个最简单的方法,也是程序代码中经常见同事的做法是在函数中创建一个List<T>,然后对其进行赋值,最后作为函数返回值来返回。
这种做法完全正确,而且List<T>太好用了,以至于我们可以用它来解决大部分问题,一个简单而典型的例子如下(例子本身没有啥意思,仅作演示之用):
IEnumerable<string> GetStrings() { List<string> list = new List<string>(); for (int i = 0; i < 10; i++) { list.Add(i.ToString()); } return list; }
然而,在任意创建一个List<T> 之前,或许存在某种更简单或更优雅的方法。
yield return 生成IEnumerable<T>
yield return 是C#的一个关键字,两者必须结合在一起使用,表示生成IEnumerable<T>的一个元素。因此,很多情况下yield return可以让我们减少新创建List<T>的几率。基于yield return,前面的例子可以修改如下:
IEnumerable<string> GetStrings() { for (int i = 0; i < 10; i++) { yield return i.ToString(); } }
如此,程序则“优雅”许多。
如何生成一个空的IEnumerable<T>
经常见到的一些例子是生成一个空的List<T> 然后返回之。举例如下:
IEnumerable<string> GetStrings() { return new List<string>(); }
代码没任何问题,但总有那么点别扭:一个空的List<T>似乎生成的没必要。事实上,C#也为这种情况作了“优雅”的设计:
IEnumerable<string> GetStrings() { yield break; }
对,没错!就是yield break,一个简单的关键字让程序“优雅”。事实上,yield return 和yield break结合起来可以处理复杂的逻辑,从而轻松的让函数返回IEnumerable<T>而尽量减少不必要的List<T>的中间变量。
一点观点
不要对语法糖抱有太多的成见,只要好用,为什么不去用呢?糖放在那儿,有谁不喜欢吃呢?