我经常遇到如下代码:
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
?
您仍然需要检查 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();
}
List<T>.ForEach(Action<T>)
(或您自己的 IEnumerable<T>.ForEach
扩展方法)一起使用。
List<string> items = null;
items?.ForEach(item =>
{
// ...
});
这里真正的要点应该是序列一开始就应该几乎不为空。只需使其成为所有程序中的不变量,即如果您有一个序列,则它永远不会为空。它始终被初始化为空序列或其他真实序列。
如果一个序列永远不为空,那么显然你不需要检查它。
实际上这里有一个功能请求:https://github.com/dotnet/csharplang/discussions/1081#issuecomment-443209795 回答也很合乎逻辑:
我认为大多数 foreach 循环是 编写的目的是迭代 非空集合。如果你试试 迭代 null 你应该得到 你的异常,这样你就可以修复 你的代码。
你总是可以用空列表来测试它......但这是我在 msdn 网站上找到的
foreach-statement:
foreach ( type identifier in expression ) embedded-statement
如果表达式的值为 null,则抛出 System.NullReferenceException。
您可以将 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);
这并不是多余的。在运行时,项目将被转换为 IEnumerable 并调用其 GetEnumerator 方法。这将导致取消引用失败的项目
你确实需要这个。否则,当
foreach
访问容器以设置迭代时,您将收到异常。
在幕后,
foreach
使用在集合类上实现的接口来执行迭代。通用的等效接口是here。
C# 的 foreach 语句 语言(对于 Visual Basic 中的每种语言) 隐藏了复杂性 枚举器。因此,使用 foreach 推荐而不是直接 操作枚举器。
测试是必要的,因为如果集合为null,foreach会抛出NullReferenceException。其实很简单,可以尝试一下。
List<string> items = null;
foreach(var item in items)
{
Console.WriteLine(item);
}
第二个将抛出一个
NullReferenceException
并显示消息 Object reference not set to an instance of an object.
正如这篇微软文章中提到的,你需要检查它是否为空。
请勿使用计算结果为 null 的表达式。
在 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 括号内进行此检查。