[英]Unexpected Foreach behavior C#
實際上, if statement
條件為true
, if statement
內的所有指令后, foreach loop
發生意外行為。 我試圖對if語句進行注釋,然后一切正常(將所有元素都迭代到ienumerable中)。 有人可以解釋我為什么?
var allRef = projDefinition
.Element(msbuild + "Project")
.Elements(msbuild + "ItemGroup")
.Elements(msbuild + "COMReference")
.Where(refElem => find.Any(f => refElem.FirstAttribute.Value.ToLower().Contains(f)))
.Select(refElem => refElem);
foreach (var xElement in allRef)
{
var name = xElement.FirstAttribute.Value;
var dllPath = dllFiles.FirstOrDefault(dll => dll.ToLower().Contains(name.ToLower()));
if (dllPath != null)
{
var dllName = dllPath.Substring(dllPath.LastIndexOf('\\') + 1, dllPath.LastIndexOf('.') - dllPath.LastIndexOf('\\') - 1);
xElement.Remove();
XElement elem = new XElement(msbuild + "Reference", new XAttribute("Include", dllName));
elem.Add(new XElement(msbuild + "HintPath", HintPath.GetHintPath(dllPath)));
elem.Add(new XElement(msbuild + "EmbedInteropTypes", "False"));
projDefinition.Root.Elements(msbuild + "ItemGroup").ElementAt(0).Add(elem);
}
}
projDefinition.Save(fullProjectPath);
您正在遍歷allRef
同時使用xElement.Remove
將其xElement.Remove
,這與循環迭代器混在一起。
基本上, foreach
在幕后創建IEnumerator
,並使用它從當前元素移到下一個元素。 您正在通過從集合中刪除元素,同時仍要遍歷它來打擾它。
它不會導致異常,但是您的循環將導致意外行為,例如不遍歷所有元素。
您可能需要閱讀foreach的工作原理
解決此類問題的簡單方法是添加.ToList()
(如@Ivan Stoev在評論中所述)。 之所以有效,是因為它創建了新列表,因此foreach
迭代器將創建到該新列表,而不是您的allRef
。 這意味着您可以安全地從allRef
刪除元素。
有關其具體工作方式的更多詳細信息, XDocument
本質上類似於節點的“鏈接列表”。 每個元素都有對其同級及其父級的引用。
各種查詢(例如Elements
)都使用迭代器塊,並且被懶惰地求值。 您可以在參考資料中關注此內容。
在當前循環變量上調用Remove
,該元素將從文檔樹中刪除。 它對其父級及其同級的引用現在都為null
。 當迭代器作為foreach
循環的一部分在對MoveNext
的調用上恢復時,無處可走。 迭代完成。
如評論和其他答案中所述,在迭代之前簡單地調用ToList
將解決問題,因為它將迭代您的查詢並將其緩存在新列表中。 以后從文檔中刪除節點不會影響列表的內容。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.