1

コレクション内のすべての要素を削除したかったのですが、表示されなかったため.RemoveAll、以下のコードを使用しました。

int number = addressBook.Items.Count;
System.Collections.IEnumerator enumerator = ...
while (enumerator.MoveNext())
{
  target = enumerator.Current as Outlook.ContactItem;
  target.Delete();
}

ただし、コレクションに残っている要素の数は、プログラムの実行ごとに約半分になっていることに気付きました。私の結論は、.Delete()それ自体が次の要素にスキップするということでした。つまり.MoveNext()、ループの条件が次の要素ジャンプするということです。

そこで、次のように列挙子をリセットしようとしました。

int number = addressBook.Items.Count;
System.Collections.IEnumerator enumerator = ...
while (enumerator.MoveNext())
{
  target = enumerator.Current as Outlook.ContactItem;
  target.Delete();
  enumerator.Reset();
}

ただし、確認した.Countところ、最後の要素が削除され、列挙子がリセットされた後、残っている要素の数はまだ1であることがわかりました。そしてもちろん、私の顔に例外がスローされました。

この写真には何が欠けていますか?それは何十年も前に報告され解決されるため、バグではないことはわかっています...

4

4 に答える 4

3

IEnumerator は、基になるコレクションが変更されない限り使用できます。それが変更されるとすぐに (たとえば、そこから要素を削除することによって)、列挙子は回復不能に無効化されます。

1 つの列挙子を使用してコレクションを変更しながら参照することはできず、Reset はそれを助けません。毎回新しい列挙子を作成するだけです。たとえば、次のようなものが機能する可能性があります。

while (addressBook.Items.Count > 0)
{
    foreach(Outlook.ContactItem target in ...)
    {
        target.Delete();
        break; // <-- !
    }
}
于 2012-09-07T12:53:15.860 に答える
1

Marc Gravell's Answerを参照してください。

リセットは冗長です。そのため、イテレータ ブロックがリセット時に例外をスローすることが言語仕様の要件になっています。正しいことは、単純に古い反復子を破棄して解放し、GetEnumerator を再度呼び出すことです。またはそれ以上: すべてのデータが繰り返し可能であるとは限らないため、2 回読み取る必要はありません。

次のリンクを参照してください。

IEnumerator.Reset() メソッドが呼び出されたときに、foreach がコレクションを反復処理している間、コレクションからアイテムを追加/削除できませんか?

IEnumerator を使用してアイテムを削除する

この助けを願っています..

于 2012-09-07T12:52:07.437 に答える
1

2つのこと。

  1. 各アイテムを削除した後に再インスタンス化する限り、列挙子を使用してすべてのアイテムを削除できるはずです。LINQ を使用すると、次のようになります。

    while (addressBook.Items.Count > 0)
    {
        addressBook.Items
            .OfType<Outlook.ContactItem>()
            .Last()
            .Delete();
    }
    
  2. MSDN によると、実際には最後のアイテムから始まるアイテムを削除する必要があります: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.outlook._contactitem.delete.aspx

于 2012-09-07T13:20:43.537 に答える