1

このコードは機能します:

var element = XElement.Parse("<div><span><em>Content</em></span><span><em>Content2</em></span></div>");

var spans = element.Descendants("span").ToList();

foreach(var span in spans)
{
    span.ReplaceWith(span.Nodes());
}

これはそうではなく、「オブジェクト参照がオブジェクトのインスタンスに設定されていません」というエラーが発生します。

var element = XElement.Parse("<div><span><em>Content</em></span><span><em>Content2</em></span></div>");

var spans = element.Descendants("span");

foreach(var span in spans)
{
    span.ReplaceWith(span.Nodes());
}

唯一の違いは、子孫ノードのリストを作成するときに「ToList()」を削除したことです。どうしてこれなの?

IQueryable は IEnumerable を実装しており、繰り返し実行すると遅延実行が強制されると思ったのに、なぜ「ToList()」がここで違いを生んでいるのでしょうか?

4

1 に答える 1

4

2 番目のケースでは、反復処理中にコレクションを変更してspansいるため、悪いことが起こります。覚えている次のものをあなたに与えようとしているのかもしれませspanんが、あなたはすでにそれを取り除いています。

(リストのようなコア コレクションでは、コレクションが変更されたことを明示的に示す例外が発生します。たとえば、 にはList<.>、リストが変更されるたびに変更されるバージョン番号があります。ToNextリスト列挙子を呼び出すと、バージョンが変更された場合、例外がスローされます。

LINQ-to-XML では、開発者はこの種の動作を追加しなかったようです)。

ToList最初のケースでは、元のツリーを変更しても、によって作成されたリストは変更されません。

私はこのようなことを試してみます:

XElement span = null; // or whatever class this should be
while ((span = element.Descendants("span").FirstOrDefault()) != null)
    span.ReplaceWith(span.Nodes());

つまり、すべてのスパンを一度に取得してから置き換えるのではなく、スパンを 1 つずつ置き換えます。

于 2012-10-24T12:30:24.907 に答える