在 foreach 之前(项目中的 T 项目)是否是多余的?

我经常遇到下面这样的代码:

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

基本上,if条件确保只有在 items不为空时才执行 foreach块。我想知道是否真的需要 if条件,或者 foreach将处理的情况下,如果 items == null

我是说,我能不能只写

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

而不用担心 items是否为空?if条件是多余的吗?或者这取决于 items类型或者可能也取决于 T

80806 次浏览

foreach访问容器来设置迭代时,您会得到一个异常。

在表面下,foreach使用 在集合类上实现的接口来执行迭代。

C # 的 foreach 语句 语言(对应 VisualBasic 中的每种语言) 隐藏了 因此,使用 foreach 建议,而不是直接 操纵枚举数。

这不是多余的。在运行时,项将强制转换为 IEnumable,并调用其 GetEnumerator 方法。这将导致对将失败的项的解引用

实际上,这里有一个特性请求: (http://github.com/dotnet/csharplang/forum/1081 # issues commment-443209795) rel = “ nofollow norefrer”> https://github.com/dotnet/csharplang/discussions/1081#issuecomment-443209795 这个回答是相当合乎逻辑的:

我觉得大多数 foreach 循环都是 为了迭代一个 非空集合。如果您尝试 遍历 null 时,应该得到 您的异常,以便您可以修复 你的密码。

测试是必要的,因为如果集合为 null,foreach 将引发 NullReferenceException。其实很容易就可以试试。

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

第二个将抛出带有消息 Object reference not set to an instance of an object.NullReferenceException

如前所述,你需要检查 给你是否为空。

不要使用计算结果为空的表达式。

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

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

如果表达式的值为 null,则引发 System.NullReferenceException。

你仍然需要检查如果(项目!= null)否则将得到 NullReferenceException。但是你可以这样做:

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

但是您可能会检查它的性能。所以我仍然喜欢先使用 if (item! = null)。

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

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

真正的收获应该是 一个序列几乎从一开始就不应该是空的。只要在你所有的程序中使它成为一个不变量,如果你有一个序列,它永远不会为空。它总是被初始化为空序列或其他真正的序列。

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

您可以在扩展方法中封装 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);

在 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 括号内进行这个检查。

使用 C # 6,你可以将新的 null 条件运算符与 List<T>.ForEach(Action<T>)(或者你自己的 IEnumerable<T>.ForEach扩展方法)一起使用。

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

人们接受的答案已经过时了。 现在,可空类型得到了广泛的应用,它可以帮助编译器理解您要达到的目标(并避免错误)。

这意味着你的清单可能是这样的:

List<Item>? list

或者... 这个:

List<Item> list

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

物品也是如此:

List<Item?> list

或者... 这个:

List<Item> list

只有在前一种情况下,才需要检查项的可空性。

当然,最后你会看到这个:

List<Item?>? list

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

==================

编辑: 一张图片胜过1000字

enter image description here

enter image description here

enter image description here