我有这个代码正在游戏的每一帧运行:
foreach (var repeaterAction in conditionTimes.Keys)
{
if (repeaterAction.Condition() == true)
{
if (conditionTimes[repeaterAction] == TimeSpan.Zero)
{
repeaterAction.Action();
}
else if (conditionTimes[repeaterAction] >= repeaterAction.InitialLapse)
{
repeaterAction.Action();
conditionTimes[repeaterAction] -= repeaterAction.ActionInterval;
}
conditionTimes[repeaterAction] += gameTime.ElapsedGameTime;
}
else
{
conditionTimes[repeaterAction] = TimeSpan.Zero;
}
}
这给了我以下错误:
收藏被修改;枚举操作可能无法执行。
有没有办法修改foreach循环中键值对中的值,而不是每帧都复制Dictionary?
答案 0 :(得分:13)
我建议不要尝试修改集合,同时使用字典循环它,但是可以使用直接密钥访问。只需在.ToArray()
中conditionTimes.Keys
之后添加foreach
,然后密钥就会成为一个单独的集合,您可以修改字典:
foreach (var repeaterAction in conditionTimes.Keys.ToArray())
{
if (repeaterAction.Condition() == true)
{
if (conditionTimes[repeaterAction] == TimeSpan.Zero)
{
repeaterAction.Action();
}
else if (conditionTimes[repeaterAction] >= repeaterAction.InitialLapse)
{
repeaterAction.Action();
conditionTimes[repeaterAction] -= repeaterAction.ActionInterval;
}
conditionTimes[repeaterAction] += gameTime.ElapsedGameTime;
}
else
{
conditionTimes[repeaterAction] = TimeSpan.Zero;
}
}
你还必须修改你的代码,这样如果密钥改变你实际上从字典中删除一个条目并添加新条目,因为密钥真的无法更改,只需删除。
同样不建议这样做。
答案 1 :(得分:3)
public class Wrapper<T>
{
public T WrappedValue { get; set; }
// *Maybe* add implicit conversions here? Icky...
}
然后你创建(比方说)一个Dictionary<string, WrappedValue<int>>
...遍历键/值对,并在包装器中更改值而不是让条目本身引用一个不同的包装。
我不认为我会推荐这个 - 使用它会很尴尬,并且容易滥用。
如果您使用.NET 4,另一个选择是使用ConcurrentDictionary
, 允许并发修改。
答案 2 :(得分:0)
对不起,你不能。
我猜你最好的办法是创建一个新词典,然后在完成foreach
循环后将其与旧词典交换。
答案 3 :(得分:0)
您应该使用其他模式来执行您尝试执行的操作,因为for each不允许您更改要循环到的枚举器。想象一下,如果你从一开始就在一个排序列表上运行foreach,你开始用key =“A”处理项目然后你转到“B”然后你将“C”改为“B”,会发生什么?你的名单已经使用了,你不再知道你在循环什么以及你在哪里。
一般来说你“可以”用for(int i = dictionary.count-1; i&gt; = 0; --i)或类似的东西来做它但这也取决于你的上下文,我真的会尝试使用另一种方法。
答案 4 :(得分:0)
在foreach
语句中枚举集合时,无法修改集合。因此,您每次都必须复制它(您只需要复制密钥)。另一种选择是始终存储单独的键列表(例如,通过将字典封装在管理它的类中)。类似的东西:
class MyDictionary<TKey, TValue>
{
private Dictionary<TKey, TValue> _dict = new Dictionary<TKey, TValue>();
private List<Keys> _keys = new List<TKey>();
public void Add(TKey key, TValue value)
{
_dict.Add(key, value);
_keys.Add(key);
}
//public bool Remove ...
//indexer...
}
当然,在并发环境中,您必须确保字典和列表已同步......
答案 5 :(得分:0)
一种常见的方法是记住要在第一个循环中更改的键,然后让第二个循环遍历记住的键并更改原始字典。这避免了创建一个包含所有元素的全新字典。