C# Foreach对不为null的IEnumerable with元素抛出NullReferenceException
我在代码中遇到了与下面代码中所示类似的情况。问题在于,出于某种原因,在foreach循环中迭代会抛出C# Foreach对不为null的IEnumerable with元素抛出NullReferenceException,c#,.net,exception,nullpointerexception,C#,.net,Exception,Nullpointerexception,我在代码中遇到了与下面代码中所示类似的情况。问题在于,出于某种原因,在foreach循环中迭代会抛出NullReferenceException 我的问题是,为什么会发生这种情况 如果我自己创建一个返回空元素的迭代器,foreach处理它,然后简单地打印出空行 以下代码的结果是:test,test,NullReferenceException 这就是问题所在: listOfA.SelectMany(x=>x.NestedCollection) 您的第二个NestedA实例没有NestedCol
NullReferenceException
我的问题是,为什么会发生这种情况
如果我自己创建一个返回空元素的迭代器,foreach
处理它,然后简单地打印出
空行
以下代码的结果是:test,test,NullReferenceException
这就是问题所在:
listOfA.SelectMany(x=>x.NestedCollection)
您的第二个NestedA
实例没有NestedCollection
,因此它正在尝试查找“空引用中的所有项”。如果手动执行此操作,则会出现完全相同的问题:
var nestedA=new nestedA();
//这将引发异常,因为nestedA.NestedCollectoin为null
foreach(nestedA.NestedCollection中的变量nestedB)
{
}
对此最简单的修复方法是将NestedCollection
设置为只读属性,但首先初始化它:
public List NestedCollection{get;}=new List();
然后,您需要修改第一个NestedA
的初始化以使用集合初始值设定项:
newnesteda
{
嵌套集合=
{
新嵌套的b{Test=“Test”},
新嵌套b{Test=“Test”}
}
}
如果您不想这样做,您可以更改SelectMany
呼叫:
var listOfB=listOfA.SelectMany(x=>x.NestedCollection??Enumerable.Empty())
这就是问题所在:
listOfA.SelectMany(x=>x.NestedCollection)
您的第二个NestedA
实例没有NestedCollection
,因此它正在尝试查找“空引用中的所有项”。如果手动执行此操作,则会出现完全相同的问题:
var nestedA=new nestedA();
//这将引发异常,因为nestedA.NestedCollectoin为null
foreach(nestedA.NestedCollection中的变量nestedB)
{
}
对此最简单的修复方法是将NestedCollection
设置为只读属性,但首先初始化它:
public List NestedCollection{get;}=new List();
然后,您需要修改第一个NestedA
的初始化以使用集合初始值设定项:
newnesteda
{
嵌套集合=
{
新嵌套的b{Test=“Test”},
新嵌套b{Test=“Test”}
}
}
如果您不想这样做,您可以更改SelectMany
呼叫:
var listOfB=listOfA.SelectMany(x=>x.NestedCollection??Enumerable.Empty())
SelectMany的实现如下所示:
公共静态IEnumerable SelectMany(
这是一个数不清的来源,
Func选择器)
{
if(source==null)
抛出错误。ArgumentNull(nameof(source));
if(选择器==null)
抛出错误.ArgumentNull(nameof(selector));
返回可枚举的。SelectManyIterator(源,选择器);
}
私有静态IEnumerable SelectManyIterator(
IEnumerable来源,
Func选择器)
{
foreach(源中的TSource source1)
{
foreach(TResult result in selector(source1))//错误在这里抛出
收益结果;
}
}
注意注释行。
选择器(source1)
将为第二个NestedA
项返回null,此行将尝试获取null项的枚举数(foreach
)。这就是出现错误的原因。SelectMany的实现如下所示:
公共静态IEnumerable SelectMany(
这是一个数不清的来源,
Func选择器)
{
if(source==null)
抛出错误。ArgumentNull(nameof(source));
if(选择器==null)
抛出错误.ArgumentNull(nameof(selector));
返回可枚举的。SelectManyIterator(源,选择器);
}
私有静态IEnumerable SelectManyIterator(
IEnumerable来源,
Func选择器)
{
foreach(源中的TSource source1)
{
foreach(TResult result in selector(source1))//错误在这里抛出
收益结果;
}
}
注意注释行。
选择器(source1)
将为第二个NestedA
项返回null,此行将尝试获取null项的枚举数(foreach
)。这就是为什么会出现错误。要补充现有答案:
编译优化和运行时优化可能会导致报告行号不准确。不仅要检查可枚举项,还要检查foreach主体是否存在可能的未引用空值,特别是在对(静态声明的)数组进行迭代时。要补充现有答案,请执行以下操作:
编译优化和运行时优化可能会导致报告行号不准确。不仅要检查可枚举项,还要检查foreach主体是否存在可能的未引用空值,特别是在对(静态声明的)数组进行迭代时。这是否回答了您的问题@SirRufo不,我知道NullReferenceException是什么,但是我不知道为什么会发生这种情况。阅读该链接的答案,你就会知道如何修复它。这是否回答了你的问题@SirRufo不,我知道什么是NullReferenceException,但是我不知道为什么会发生这种情况。阅读该链接中的答案,你就会知道如何修复它。我认为SelectMany会首先使用两个项,然后在最后一个位置添加一个null(合并两个集合),这样它就会被``if(item!=null)``捕获,并不是说它会尝试迭代null。@MPal:No,
SelectMany
在展平之前从未将“null引用”转换为“具有默认值的单个元素的集合”。我可以理解它可能会自动将空引用视为一个空集合,但是
using System;
using System.Collections.Generic;
using System.Linq;
public class NestedB
{
public string Test {get;set;}
}
public class NestedA
{
public List<NestedB> NestedCollection {get;set;}
}
public class Program
{
public static void Main()
{
var listOfA = new List<NestedA>
{
new NestedA
{
NestedCollection = new List<NestedB>
{
new NestedB {Test = "test"},
new NestedB {Test = "test"}
}
},
new NestedA ()
};
var listOfB = listOfA.SelectMany(x => x.NestedCollection);
foreach (var item in listOfB)
{
if (item != null)
{
Console.WriteLine(item.Test);
}
}
}
}
Unhandled exception. System.NullReferenceException: Object reference not set to an instance of an object.
at System.Linq.Enumerable.SelectManySingleSelectorIterator`2.MoveNext()
at Program.Main()
Command terminated by signal 6