扩展LINQ以接受可以为空的枚举

Mah*_*amy 40 .net c# linq

在使用Linq扩展时,看到这样的代码是正常的:

IEnumerable<int> enumerable = GetEnumerable();
int sum = 0;
if (enumerable != null)
{
    sum = enumerable.Sum();
}
Run Code Online (Sandbox Code Playgroud)

为了提高代码质量,我编写了以下扩展方法来检查可以为空的枚举并打破linq执行.

public static IEnumerable<T> IgnoreIfEmpty<T>(this IEnumerable<T> enumerable)
{
    if (enumerable == null) yield break;
    foreach (var item in enumerable)
    {
        yield return item;
    }
}
Run Code Online (Sandbox Code Playgroud)

所以,我可以重构代码,如下所示:

var sum = GetEnumerable().IgnoreIfEmpty().Sum();
Run Code Online (Sandbox Code Playgroud)

我现在的问题:

  1. 在运行时我的扩展方法有哪些惩罚?
  2. 以这种方式扩展linq是一个好习惯吗?

更新: 我的目标框架是:3.5

Yuv*_*kov 40

在运行时我的扩展方法有哪些惩罚?

你的扩展方法被转换为状态机,所以它的开销很小,但这不应该是明显的.

以这种方式扩展linq是一个好习惯吗?

在您的问题中,您声明:

在使用Linq扩展时,看到这样的代码是正常的(在此处插入可枚举的null检查)

我不同意.在常见的做法表示不返回null,其中的IEnumerable<T>预期.大多数情况下,应该返回一个空集(或IEnumerable),留null特殊的,因为空不空.这会使您的方法完全冗余.Enumerable.Empty<T>在需要的地方使用

  • 绝对同意将空集合优先于null.对于任何事物,不仅仅是集合,应该谨慎使用Null.丢失了多少错误来自空引用. (11认同)

Bas*_*Bas 29

  1. 您将有一个方法调用开销,除非您在紧密循环或性能标准场景中运行它,否则它将是微不足道的.与数据库调用或写入文件系统相比,它只是一个阴影.请注意,该方法可能不会被内联,因为它是一个枚举器.
  2. 这完全取决于可读性/可维护性.当我看到时,我期待发生什么GetEnumerable().IgnoreIfEmpty().Sum();?在这种情况下,它是有道理的.

请注意,使用C#6,我们可以使用以下语法:GetEnumerable()?.Sum()返回一个int?.您可以编写GetEnumerable()?.Sum() ?? 0GetEnumerable()?.Sum().GetValueOrDefault()获取一个默认为零的非空整数.

如果你真的关心性能,你也可以稍微重构一下你的方法,这样它就不是一个枚举器.虽然我不知道JIT编译器的"神秘"逻辑,但这可能会增加内联的机会:

public static IEnumerable<T> IgnoreIfEmpty<T>(this IEnumerable<T> enumerable)
{
    if (enumerable == null) return Enumerable.Empty<T>();
    return enumerable;
}
Run Code Online (Sandbox Code Playgroud)

更一般地说,扩展Linq,我认为只要代码有意义就完全没问题.MSDN甚至有一篇关于它的文章.如果你看一下标准Where,Select在LINQ的方法,而忘记了他们曾经出现过性能优化,这些方法都是大多是一班轮方法.

  • 实际上我认为null条件运算符应该在.NET 3.5上运行正常,只要你的编译器兼容C#6:http://stackoverflow.com/questions/28921701/does-c-sharp-6-0-work-for-净4-0 (2认同)

w.b*_*w.b 14

您可以跳过其他扩展方法并使用null合并运算符 - 这就是它的用途,并且一次性检查可空性应该比另一个状态机更有效:

IEnumerable<int> enumerable = GetEnumerable();
int sum = 0;

sum = (enumerable ?? Enumerable.Empty<int>()).Sum();
Run Code Online (Sandbox Code Playgroud)