Check for null in foreach loop
是否有更好的方法来执行以下操作:在继续循环之前,我需要检查file.headers上是否存在空值。
1 2 3 4 5 6 7
| if (file.Headers != null)
{
foreach (var h in file.Headers)
{
//set lots of properties & some other stuff
}
} |
简而言之,由于我的代码中出现的缩进级别,在if中编写foreach看起来有点难看。
是可以评估的东西
1 2 3 4
| foreach(var h in (file.Headers != null))
{
//do stuff
} |
号
可能吗?
- 您可以在这里查看:stackoverflow.com/questions/6937407/…
- stackoverflow.com/questions/872323/…是另一个想法。
- @阿德里安法丘,我觉得完全不同。在为每个集合执行之前,问题首先检查集合是否为空。链接检查集合中的项是否为空。
- 类似于stackoverflow.com/q/3088147/80161和stackoverflow.com/q/6455311/80161
- C 8可以简单地具有某种类型的空条件foreach,即类似这样的语法:foreach?(集合中的var i)我认为这是一个足够常见的场景来证明这一点,并且考虑到最近在语言中添加了空条件,所以这里它有意义吗?
就像对rune的建议稍加修饰一样,您可以创建自己的扩展方法:
1 2 3 4
| public static IEnumerable<T> OrEmptyIfNull<T>(this IEnumerable<T> source)
{
return source ?? Enumerable.Empty<T>();
} |
。
然后你可以写:
1 2 3
| foreach (var header in file.Headers.OrEmptyIfNull())
{
} |
。
根据口味更改名称:)
- @kjbartel的答案(在"stackoverflow.com/a/32134295/401246"上)是最好的解决方案,因为它不包括:a)包括性能下降(即使不是null的情况下)将整个回路退化为IEnumerable的LCD(作为使用??会),b)要求在每个项目中添加一个扩展方法,或c)要求避免nullIEnumerables(pffft!普里兹!smh.)首先(cuz null表示不适用,而空列表则表示适用,但目前是空的!也就是说,如果员工没有任何收入,他们可能会有非销售佣金或销售佣金为空)。
假设file.headers中的元素类型不是,您可以这样做
1 2 3
| foreach(var header in file.Headers ?? Enumerable.Empty<T>()){
//do stuff
} |
如果file.headers为空,这将创建一个空的可枚举的t。但是,如果文件的类型是您拥有的类型,我会考虑改为更改EDOCX1的getter(0)。null是unknown的值,因此,如果可能的话,不使用空值作为"我知道没有元素",当空值(原本)应解释为"我不知道是否有元素"时,使用空的集合来表示您知道集合中没有元素。那也会是干的,因为你不必经常做空检查。
作为对jons建议的后续操作,您还可以创建一个扩展方法,将上述代码更改为
1 2 3
| foreach(var header in file.Headers.OrEmptyIfNull()){
//do stuff
} |
号
在你不能改变吸气剂的情况下,这将是我自己的首选,因为它通过给操作命名来更清楚地表达意图(orEmptyifNull)
上述扩展方法可能会使优化程序无法检测到某些优化。具体来说,使用方法重载与IList相关的那些可以消除
1 2 3 4
| public static IList<T> OrEmptyIfNull<T>(this IList<T> source)
{
return source ?? Array.Empty<T>();
} |
- @kjbartel的答案(在"stackoverflow.com/a/32134295/401246"上)是最好的解决方案,因为它不包括:a)包括性能下降(即使不是null的情况下)将整个回路退化为IEnumerable的LCD(作为使用??会),b)要求在每个项目中添加一个扩展方法,或c)要求避免nullIEnumerables(pffft!普里兹!smh.)首先(cuz null表示不适用,而空列表则表示适用,但目前是空的!也就是说,如果员工没有任何收入,他们可能会有非销售佣金或销售佣金为空)。
- @除了一个空检查,枚举器不为空的情况没有处罚。在确保可枚举不为空的同时避免该检查是不可能的。上面的代码要求IEnumerable的头文件比foreach的要求更严格,但比您链接到的答案中的List的要求更严格。它们在测试可枚举是否为空时具有相同的性能惩罚。
- 我是根据埃里克·利珀特对弗拉德·贝兹登的回答所作的评论而提出的"LCD"问题,与KJBartel的回答是一样的:"@codeinchaos:ah,我现在明白你的意思了。当编译器检测到"foreach"正在列表或数组上迭代时,它可以优化foreach以使用值类型枚举器或实际生成"for"循环。当强制枚举一个列表或空序列时,它必须返回到"最小公分母"codegen,在某些情况下,它可能会变慢并产生更多的内存压力…."。同意要求List。
- @Tom答案的前提是file.headers是一个IEnumerable在这种情况下,编译器无法进行优化。然而,为了避免这种情况,扩展扩展扩展方法解决方案是相当直接的。参见编辑
坦率地说,我建议:只要接受null测试。null测试只是一个brfalse或brfalse.s测试;其他所有测试都将涉及更多的工作(测试、分配、额外的方法调用、不必要的GetEnumerator()、MoveNext()和Dispose()迭代器等)。
if测试简单、明显、有效。
- 不过,您确实提出了一个有趣的观点,Marc,我目前正在寻找减少代码缩进级别的方法。但当我需要注意表现的时候,我会记住你的评论。
- 这是马克的一个简短说明。在我问了这个问题并需要实现一些性能增强的几年后,您的建议非常有用。谢谢你
迭代之前的"if"很好,很少有"pretty"语义可以降低代码的可读性。
不管怎样,如果压痕干扰了您,您可以更改if以检查:
1 2
| if(file.Headers == null)
return; |
。
只有当headers属性中有一个真值时,才能访问foreach循环。
我可以考虑的另一个选项是在foreach循环中使用空合并运算符,并完全避免空检查。样品:
1 2 3 4 5 6
| List <int> collection = new List <int>();
collection = null;
foreach (var i in collection ?? Enumerable .Empty<int>())
{
//your code here
} |
(将集合替换为真正的对象/类型)
- 如果在if语句之外有任何代码,则第一个选项将不起作用。
- 我同意,与创建一个新列表相比,if语句实现起来既简单又便宜,只是为了美化代码。
对于这些场景,我使用了一个很好的小扩展方法:
1 2 3 4 5 6 7
| public static class Extensions
{
public static IList <T > EnsureNotNull <T >(this IList <T > list )
{
return list ?? new List <T >();
}
} |
鉴于头是列表类型,您可以执行以下操作:
1 2 3 4
| foreach(var h in (file.Headers.EnsureNotNull()))
{
//do stuff
} |
。
- 您可以使用??操作符并缩短返回语句到return list ?? new List;的时间。
- @Wolfgangziegler,如果我正确理解你的样本中的null的测试,那么不需要file.Headers.EnsureNotNull() != null的测试,甚至是错误的?
使用空条件运算符和foreach(),它的工作速度比标准foreach循环快。不过,您必须将集合强制转换为列表。
1
| listOfItems?.ForEach(item => // ... ); |
。
- 请在您的答案周围添加一些解释,明确说明此解决方案的工作原因,而不仅仅是代码一行程序。
在某些情况下,我更倾向于使用另一个通用变量,假定默认集合构造函数通常返回空实例。
最好将此方法命名为NewIfDefault。它不仅对集合有用,因此类型约束IEnumerable可能是多余的。
1 2 3 4 5
| public static TCollection EmptyIfDefault <TCollection, T >(this TCollection collection )
where TCollection : class, IEnumerable <T >, new()
{
return collection ?? new TCollection ();
} |