簡體   English   中英

意外的Foreach行為C#

[英]Unexpected Foreach behavior C#

實際上, if statement條件為trueif 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM