在 foreach(T item in items) 之前 if(items != null) 是多余的吗?

问题描述 投票:0回答:13

我经常遇到如下代码:

if ( items != null)
{
   foreach(T item in items)
   {
        //...
   }
}

基本上,

if
条件确保仅当
foreach
不为空时才会执行
items
块。我想知道是否真的需要
if
条件,或者
foreach
将处理
items == null
的情况。

我的意思是,我可以简单地写一下吗

foreach(T item in items)
{
    //...
}

不用担心

items
是否为空?
if
条件是多余的吗?或者这取决于 items
type
或者也取决于
T

c# iterator foreach iteration
13个回答
173
投票

您仍然需要检查 if (items != null) 否则您将得到 NullReferenceException。不过你可以这样做:

List<string> items = null;  
foreach (var item in items ?? new List<string>())
{
    item.Dump();
}

但你可以检查它的性能。所以我还是更喜欢先有 if (items != null) 。

根据 Eric 的 Lippert 建议,我将代码更改为:

List<string> items = null;  
foreach (var item in items ?? Enumerable.Empty<string>())
{
    item.Dump();
}

105
投票

使用 C# 6,您可以将新的 null 条件运算符与

List<T>.ForEach(Action<T>)
(或您自己的
IEnumerable<T>.ForEach
扩展方法)一起使用。

List<string> items = null;
items?.ForEach(item =>
{
    // ...
});

38
投票

这里真正的要点应该是序列一开始就应该几乎不为空。只需使其成为所有程序中的不变量,即如果您有一个序列,则它永远不会为空。它始终被初始化为空序列或其他真实序列。

如果一个序列永远不为空,那么显然你不需要检查它。


11
投票

实际上这里有一个功能请求:https://github.com/dotnet/csharplang/discussions/1081#issuecomment-443209795 回答也很合乎逻辑:

我认为大多数 foreach 循环是 编写的目的是迭代 非空集合。如果你试试 迭代 null 你应该得到 你的异常,这样你就可以修复 你的代码。


6
投票

你总是可以用空列表来测试它......但这是我在 msdn 网站上找到的

foreach-statement:
    foreach   (   type   identifier   in   expression   )   embedded-statement 

如果表达式的值为 null,则抛出 System.NullReferenceException。


3
投票

您可以将 null 检查封装在扩展方法中并使用 lambda:

public static class EnumerableExtensions {
  public static void ForEach<T>(this IEnumerable<T> self, Action<T> action) {
    if (self != null) {
      foreach (var element in self) {
        action(element);
      }
    }
  }
}

代码变为:

items.ForEach(item => { 
  ...
});

如果您只想调用一个接受项目并返回的方法,则可以更简洁

void

items.ForEach(MethodThatTakesAnItem);

2
投票

这并不是多余的。在运行时,项目将被转换为 IEnumerable 并调用其 GetEnumerator 方法。这将导致取消引用失败的项目


1
投票

你确实需要这个。否则,当

foreach
访问容器以设置迭代时,您将收到异常。

在幕后,

foreach
使用在集合类上实现的接口来执行迭代。通用的等效接口是here

C# 的 foreach 语句 语言(对于 Visual Basic 中的每种语言) 隐藏了复杂性 枚举器。因此,使用 foreach 推荐而不是直接 操作枚举器。


0
投票

测试是必要的,因为如果集合为null,foreach会抛出NullReferenceException。其实很简单,可以尝试一下。

List<string> items = null;
foreach(var item in items)
{
   Console.WriteLine(item);
}

0
投票

第二个将抛出一个

NullReferenceException
并显示消息
Object reference not set to an instance of an object.


0
投票

正如这篇微软文章中提到的,你需要检查它是否为空。

请勿使用计算结果为 null 的表达式。


0
投票

接受的答案已经过时了。 如今,可空类型被广泛使用,可以帮助编译器理解您想要实现的目标(并避免错误)。

这意味着您的列表可能是这样的:

List<Item>? list

...或者...这个:

List<Item> list

您只需要检查前一种情况的可空性。

同样的事情也适用于物品:

List<Item?> list

...或者...这个:

List<Item> list

您只需要检查前一种情况的项目是否可为空。

当然最后你得到了这个:

List<Item?>? list

任何内容(列表和项目)都可能为空。


-1
投票

在 C# 6 中你可以这样写:

// some string from file or UI, i.e.:
// a) string s = "Hello, World!";
// b) string s = "";
// ...
var items = s?.Split(new char[] { ',', '!', ' ' }) ?? Enumerable.Empty<string>();  
foreach (var item in items)
{
    //..
}

这基本上是 Vlad Bezden 的解决方案,但使用 ??表达式始终生成一个不为空的数组,因此在 foreach 中幸存下来,而不是在 foreach 括号内进行此检查。

© www.soinside.com 2019 - 2024. All rights reserved.