![](/img/trans.png)
[英]foreach looping variable throws NullReferenceException but Enumerable is not null
[英]Foreach throws NullReferenceException on not null IEnumerable with elements
我在代碼中遇到了與下面代碼中類似的情況。 問題是由於某種原因在 foreach 循環中迭代會拋出NullReferenceException
。
我的問題是,為什么會發生這種情況?
如果我創建自己返回空元素的迭代器, foreach
會處理它,並簡單地prints
空行。
以下代碼的結果是: test, test, NullReferenceException 。
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
這就是問題:
listOfA.SelectMany(x => x.NestedCollection)
您的第二個NestedA
實例沒有NestedCollection
,因此它試圖查找“null 參考中的所有項目”。 如果您手動執行此操作,您將遇到完全相同的問題:
var nestedA = new NestedA();
// This will throw an exception, because nestedA.NestedCollectoin is null
foreach (var nestedB in nestedA.NestedCollection)
{
}
最簡單的解決方法是將NestedCollection
只讀屬性,但將其初始化為:
public List<NestedB> NestedCollection { get; } = new List<NestedB>();
然后,您需要修改第一個NestedA
的初始化以使用集合初始化程序:
new NestedA
{
NestedCollection =
{
new NestedB { Test = "test" },
new NestedB { Test = "test" }
}
}
如果您不想這樣做,則可以改為更改SelectMany
調用:
var listOfB = listOfA.SelectMany(x => x.NestedCollection ?? Enumerable.Empty<NestedB>())
SelectMany
的實現是這樣的:
public static IEnumerable<TResult> SelectMany<TSource, TResult>(
this IEnumerable<TSource> source,
Func<TSource, IEnumerable<TResult>> selector)
{
if (source == null)
throw Error.ArgumentNull(nameof (source));
if (selector == null)
throw Error.ArgumentNull(nameof (selector));
return Enumerable.SelectManyIterator<TSource, TResult>(source, selector);
}
private static IEnumerable<TResult> SelectManyIterator<TSource, TResult>(
IEnumerable<TSource> source,
Func<TSource, IEnumerable<TResult>> selector)
{
foreach (TSource source1 in source)
{
foreach (TResult result in selector(source1)) // The error throws here
yield return result;
}
}
注意注釋行。 selector(source1)
將為第二個NestedA
項返回 null,並且此行將嘗試獲取 null 項( foreach
)的枚舉器。 這就是你得到錯誤的原因。
為了補充現有的答案:
編譯優化和運行時優化可能會導致報告的行號不准確。 不僅要檢查可枚舉對象,還要檢查 foreach 主體中可能的取消引用空值,尤其是在迭代(靜態聲明的)數組時。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.