2

これは悪いプログラミングと見なされるかもしれませんが、.net 4 より前は、次のようなコードを頻繁に使用していました。

    enemyList.ForEach(delegate(Enemy e)
    {
        e.Update();
        if (someCondition)
              enemyList.Remove(e);
    });

今、私はいくつかの古いプロジェクトを更新しています. ForEachが削除されて以来、変更する必要があるコードがたくさんあります..今、私は ForEach を使用できるようにする拡張機能を持っています:

    public static void ForEach<T>(this IEnumerable<T> sequence, Action<T> action)
    {
        if (sequence == null) throw new ArgumentNullException("sequence");
        if (action == null) throw new ArgumentNullException("action");
        foreach (T item in sequence)
            action(item);
    }

私はこれを行うことができることを知っています:

    var index = 0;
    while(index < enemyList.Count)
    {
        if(condition)
            enemyList.RemoveAt(index);
        else
            index++;
    }

しかし、それらのいくつかは、そのように書き直すのが面倒です..その機能を追加して、そのリストを繰り返し処理し、必要な項目を削除して、それらのすべての関数を書き直して編集する必要はありませんか? ? 私はまだコーディングの初心者だと思っていますが、これを理解することはできません..どんな助けでも大歓迎です!

** * ** * ***編集** * ** * ** *

要するに、多くのコードを書き直すことになると思います..プロジェクトから取り出したばかりの、このようなコードがたくさんあります。

            GameplayScreen.gameWorld.shipList.ForEach(delegate(Ship s)
            {
                if (eS.originalShipsID == s.shipID)
                {
                    if (!eS.Alive || eS.health <= 0)
                    {
                        // this one sunk...
                        string log = "0" + s.shipName + " was sunk in battle.. All crew and cargo were lost.";
                        AddLogEntry(log);
                        totalCrewLost += s.currentCrew;
                        GameplayScreen.gameWorld.shipList.Remove(s);
                    }
                }
            });

そのすべてを書き直す必要がない方法があることを望んでいました..だから、どうやらコーディング方法を更新して変更する時が来ました。ありがとう!

4

5 に答える 5

9

リストのRemoveAllメソッドを使用します。

コードを次のようにリファクタリングできます。

enemyList.RemoveAll(enemy => enemy.SomeCondition);

ループよりも優れているだけでなく、メソッドwhileよりもかなり優れていると思います。Foreach

于 2013-03-20T21:02:25.850 に答える
3

できません。唯一の方法は、削除するアイテムを別のリストに追加してから、そのリストを繰り返し処理し、最初の繰り返しの後にそれらを削除することです。

より良いオプションは、逆の for ループを使用して値を反復処理することです。その後、最初の反復中にアイテムを安全に削除できます。

for (var i = enemyList.Count() - 1; i >= 0; i--) {
{
    if(condition) enemyList.RemoveAt(i);
}
于 2013-03-20T20:50:31.350 に答える
2

あなたはそれをたくさんすると言ったので、次のようなことをしてみませんか:

public static void RemoveIfTrue<T>(this ICollection<T> list, Func<T, bool> condition)
{
    List<T> itemsToRemove = list.Where(condition).ToList();
    foreach (var item in itemsToRemove)
    {
        list.Remove(item);
    }
}

次に、次のように使用できます。

myList.RemoveIfTrue(x => YourConditionIsTrue)

そうすれば、ロジックの重複がなくなります。

于 2013-03-20T20:55:49.080 に答える
1

これはちょっとした工夫で可能です。次に例を示します。

public static class Extensions
{
    public static void ForEach<T>(this IList<T> list, Action<T> action)
    {
        for (int i = 0; i < list.Count; i++)
        {
            action(list[i]);
        }
    }
}

class Program
{

    static void Main(string[] args)
    {
        List<string> vals = new List<string>(new string[] { "a", "bc", "de", "f", "gh", "i", "jk" });

        vals.ToList().ForEach<string>(delegate(string value)
        {
            if (value.Length > 1)
            {
                vals.Remove(value);
            }
        });

        vals.ToList().ForEach<string>(delegate(string value)
        {
            Console.WriteLine(value);
        });

        Console.ReadKey();
    }
}

さて、ここで言及する価値のあることがいくつかあります。まず、通常、要素はスキップされます。ただし、ToList() を呼び出すと、リストの別のコピーが作成されます。第 2 に、これを参照型でのみ行うように注意する必要があります。つまり、プリミティブ型では行わないでください。そうしないと、removeメソッドで複数の要素を削除することになります。

編集

また、おそらく投稿された代替案のいずれかが優れていることを付け加えたいと思いますが、これが可能であることは興味深いと思いました。パフォーマンスは劣りますが、おそらく既存のコードに取り掛かる方が速いでしょう。

于 2013-03-20T21:02:16.363 に答える
1

を使用している場合はList<T>、使用できますList<T>.RemoveAll(Predicate<T> match)

したがって、これを行うための組み込みのものが既にあります。

さらに良いことに、組み込みのものは、コレクションを反復しながらコレクションを変更する際の問題を回避する方法を正確に知っています。また、プライベートな内部にアクセスできるため、効率も向上します。

したがって、List クラス自体を使用するだけで、次のようなコードを記述できます。

enemies.RemoveAll(enemy => (enemy.Health <= 0));

于 2013-03-20T21:01:21.287 に答える