2017-01-04 14 views
-1

内のすべての命令の後で、条件がtrueの場合、予期しない動作をします。ループが壊れます。私はifステートメントをコメントしようとし、すべてうまく動作する(すべての要素をienumerableに反復する)。誰かがなぜ私を説明することができますか?予期しないForeachの動作C#

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); 
+2

ifブロックを通して行単位でデバッグする際に例外がありますか? – woohoo

+0

'if(dllPath!= null)'がforeachループで混乱するのですか?これがあなたの実際のコードなら、私は自分の目で見ることなくあなたが言ったことを信じません。 –

+0

人はいませんが、例外はありません。 – CRK

答えて

5

同時にあなたがループイテレータを台無しxElement.Remove、でそれから削除している間、あなたはallRefをループしています。

基本的にforeachフードの下にIEnumeratorを作成し、現在の要素から次の要素に移動するために使用します。あなたはまだそれを越えてコレクションから要素を取り除くことでそれを邪魔しています。

例外は発生しませんが、ループによってすべての要素を処理しないなどの予期しない動作が発生します。 (@Ivan Stoevがコメントで述べたように)あなたはこの種の問題のためhow does foreach works

シンプルなソリューションを読むことをお勧めします

.ToList()を追加しています。それは新しいリストを作成するので、foreachイテレータがあなたのallRefの代わりにその新しいリストに作成されるので動作します。つまり、allRefから要素を安全に削除できます。

2

具体的な仕組みの詳細については、XDocumentは本質的にノードの「リンクされたリスト」に似ています。各要素には、その兄弟およびその親に対する参照があります。

さまざまなクエリ(Elementsなど)はすべてイテレータブロックを使用し、遅延評価されます。 reference sourceでこれに従うことができます。

Removeを現在のループ変数にコールすると、要素はドキュメントツリーから削除されます。親と兄弟の参照は両方ともnullです。 foreachループの一部としてMoveNextへの呼び出しでイテレータが再開すると、どこにも行きません。反復が完了しました。

他の回答&の回答で説明したように、それを反復する前にToListを呼び出すだけで、クエリを繰り返し処理して新しいリストにキャッシュするので、問題は解決します。後で文書からノードを削除しても、リストの内容には影響しません。