120

是否有更好的方法来执行以下操作:
在继续循环之前,我需要在 file.Headers 上检查 null

if (file.Headers != null)
{
  foreach (var h in file.Headers)
  {
   //set lots of properties & some other stuff
  }
}

简而言之,由于我的代码中发生的缩进级别,在 if 中编写 foreach 看起来有点难看。

是可以评估的东西

foreach(var h in (file.Headers != null))
{
  //do stuff
}

可能的?

4

7 回答 7

152

作为对 Rune 建议的轻微修饰,您可以创建自己的扩展方法:

public static IEnumerable<T> OrEmptyIfNull<T>(this IEnumerable<T> source)
{
    return source ?? Enumerable.Empty<T>();
}

然后你可以写:

foreach (var header in file.Headers.OrEmptyIfNull())
{
}

根据口味更改名称:)

于 2012-07-31T06:40:41.253 回答
92

假设 file.Headers 中元素的类型是 T 你可以这样做

foreach(var header in file.Headers ?? Enumerable.Empty<T>()){
  //do stuff
}

如果 file.Headers 为空,这将创建一个空的 T 枚举。但是,如果文件类型是您拥有的类型,我会考虑更改 getter Headersnull是 unknown 的值,所以如果可能,当 null 实际上(/最初)应该解释为“我不知道是否有任何元素”时,而不是使用 null 作为“我知道没有元素”,而是使用空集来显示你知道集合中没有元素。这也将是 DRY'er,因为您不必经常进行 null 检查。

编辑作为 Jons 建议的后续行动,您还可以创建一个扩展方法,将上述代码更改为

foreach(var header in file.Headers.OrEmptyIfNull()){
  //do stuff
}

在您无法更改 getter 的情况下,这将是我自己的首选,因为它通过为操作命名(OrEmptyIfNull)更清楚地表达了意图

上面提到的扩展方法可能会使优化器无法检测到某些优化。具体来说,那些与 IList 相关的使用方法重载 this 可以被消除

public static IList<T> OrEmptyIfNull<T>(this IList<T> source)
{
    return source ?? Array.Empty<T>();
}
于 2012-07-31T06:37:43.337 回答
24

坦率地说,我建议:干脆接受null测试。null测试只是一个brfalseor brfalse.s; _ 其他一切都将涉及更多的工作(测试、分配、额外的方法调用、不必要的GetEnumerator(), MoveNext(),Dispose()迭代器等)。

测试简单、if明显且有效。

于 2012-07-31T06:46:54.510 回答
19

使用空条件运算符和比标准 foreach 循环更快的 ForEach()。
不过,您必须将集合转换为 List。

   listOfItems?.ForEach(item => // ... );
于 2018-02-27T11:03:42.070 回答
17

迭代之前的“if”很好,这些“漂亮”语义中很少有可以使您的代码可读性降低。

无论如何,如果缩进打扰您,您可以更改 if 来检查:

if(file.Headers == null)  
   return;

并且只有当 headers 属性存在真值时,您才会进入 foreach 循环。

我可以考虑的另一个选择是在 foreach 循环中使用 null-coalescing 运算符并完全避免 null 检查。样本:

List<int> collection = new List<int>();
collection = null;
foreach (var i in collection ?? Enumerable.Empty<int>())
{
    //your code here
}

(用你的真实对象/类型替换集合)

于 2012-07-31T06:39:35.583 回答
3

我为这些场景使用了一个不错的小扩展方法:

  public static class Extensions
  {
    public static IList<T> EnsureNotNull<T>(this IList<T> list)
    {
      return list ?? new List<T>();
    }
  }

鉴于 Headers 是列表类型,您可以执行以下操作:

foreach(var h in (file.Headers.EnsureNotNull()))
{
  //do stuff
}
于 2012-07-31T06:40:41.577 回答
0

在某些情况下,我更喜欢另一种通用变体,假设通常默认集合构造函数返回空实例。

最好命名这个方法NewIfDefault。它不仅对集合有用,因此类型约束IEnumerable<T>可能是多余的。

public static TCollection EmptyIfDefault<TCollection, T>(this TCollection collection)
        where TCollection: class, IEnumerable<T>, new()
    {
        return collection ?? new TCollection();
    }
于 2018-01-25T11:12:01.047 回答