这可能被认为是错误的编程,但在.net 4之前,我曾经大量使用类似这样的代码:
enemyList.ForEach(delegate(Enemy e)
{
e.Update();
if (someCondition)
enemyList.Remove(e);
});
现在,我正在更新一些旧项目,并且有一个 LOT 代码,因为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);
}
}
});
我只是希望有一种方法可以不必重写所有这些..所以,时间更新并改变我的代码显然方式。谢谢!
答案 0 :(得分:9)
使用列表的RemoveAll
方法。
您可以将代码重构为:
enemyList.RemoveAll(enemy => enemy.SomeCondition);
它不仅比while
循环好,我认为它比Foreach
方法好一点。
答案 1 :(得分:3)
你做不到。唯一的方法是将要删除的项添加到另一个列表中,然后迭代该列表并在初始迭代后删除它们。
更好的选择是使用反向for循环迭代值。然后,您可以在初始迭代期间安全地删除项目:
for (var i = enemyList.Count() - 1; i >= 0; i--) {
{
if(condition) enemyList.RemoveAt(i);
}
答案 2 :(得分: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)
这样你就没有一堆重复的逻辑。
答案 3 :(得分:1)
如果您使用的是List<T>
,则可以使用List<T>.RemoveAll(Predicate<T> match)
所以有一个内置的东西可以做到这一点。
更好 - 内置的人确切地知道如何避免在迭代时修改集合的问题。而且因为它可以访问私有内部,所以它也更有效。
因此,只需使用List类本身就可以编写如下代码:
enemies.RemoveAll(enemy => (enemy.Health <= 0));
答案 4 :(得分: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()可以获得列表的单独副本。其次,你应该注意只使用引用类型 - 即不使用基本类型 - 否则你将使用remove
方法删除多个元素。
修改强>
我还想补充一点,可能任何发布的替代方案都更好 - 但我认为这可以做到这一点很有意思;它性能较差,但可能更快地进入现有代码。