IEnumerable<T> 空合并扩展方法

5

我经常遇到这样的问题,即在使用foreach或LINQ查询对IEnumerable<T>进行迭代之前,需要检查它是否为null。我通常会遇到以下代码:

var myProjection = (myList ?? Enumerable.Empty<T>()).Select(x => x.Foo)...

因此,我想将这个扩展方法添加到一个扩展类中:
public static class MyExtensions 
{
    public static IEnumerable<T> AsEmptyIfNull<T>(this IEnumerable<T> source)
    {
        return source ?? Enumerable.Empty<T>();
    }
}

看到这段代码,我立刻想到一个小问题,即扩展方法的“实例方法方面”,它应该被实现为一个普通的静态方法,否则像下面这样的代码就是完全合法的:
IEnumerable<int> list = null;
list.AsEmptyIfNull();

您认为在使用它时还有其他缺点吗?
如果大量使用,这种扩展是否会导致开发人员出现某种不良趋势?


奖励问题:

您能给它提供一个更好的名称吗?:)
(英语不是我的母语,所以我不太擅长命名...)

提前感谢。


什么是问题?你不想让它合法吗?使用静态方法也可以使其合法,但我认为整个重点是要使其合法,这是通过扩展或静态方法实现的。 - recursive
@recursive:你是指“小问题”部分还是整个问题?如果是前者,我认为对于“习惯于实例方法”的人来说,阅读代码可能会有点奇怪。如果是后者,那么我的问题正是关于是否正确传播这样的扩展方法(例如在公司共享的实用程序集中),因为这可能会导致不良行为... - digEmAll
使用此扩展时,如果类型未被推断,请尝试在 .AsEmptyIfNull() 之前添加 .AsEnumerable()。另外,我更喜欢将方法称为 EmptyIfNull,因为 As 暗示着强制转换,在这里并没有发生。DefaultIfEmpty 也没有被命名为 AsDefaultIfEmpty - Palec
2个回答

7

返回一个 IEnumerable<T> 的方法应该返回一个空的集合,而不是 null。这样你就不需要这个了。

参见这个问题:返回 null 或者空集合更好?

否则,你的代码看起来还不错。


2
是的,这是正确的,但并不总是可以更改代码以获得这个结果(例如,在使用API时)。为了举一个真实的例子,尝试使用protobuf序列化一个空列表,然后对其进行反序列化:你会得到null :) - digEmAll

3
如果可以控制,返回空序列而不是null通常是一个不好的主意。如果考虑到当有人被要求生成一个集合时,返回null并不像说“集合为空”,而是“根本没有这样的集合”,这一点就不言自明了。
如果您拥有返回可枚举对象的方法,则返回空的IEnumerable(如果可能经常返回,则甚至可以是一个特殊的只读静态对象)是正确的选择。
如果您被迫使用一个习惯于在这种情况下返回null的粗鲁库,则扩展方法可能是一种解决方案,但我仍然不喜欢它。最好将粗鲁的方法封装在您自己的版本中,在人们看不到的地方进行合并。这样,您既可以方便地始终拥有可枚举对象而不是null,又可以正确地不支持“返回null”范例。

是的,也许最好的做法是封装不礼貌的库。无论如何,创建这种扩展似乎并不那么有害,对吧? - digEmAll
@digEmAll:唯一的危害就是看到这个可能会认为方法返回null而不是空集合是可以接受的,并编写自己的这种方法,从而使问题得以延续。除此之外,我没有看到任何危害。 - Jon

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