A “指数数组的边界之外。”字典上的错误(或任何内容)System.Collections
命名空间)当文档说不应抛出错误时always由于您违反了线程安全而造成的。
中的所有集合System.Collections
命名空间只允许两个操作之一发生
- 无限并发读者,0 个作者。
- 0 位读者,1 位作者。
您必须使用同步所有对字典的访问ReaderWriterLockSlim https://msdn.microsoft.com/en-us/library/system.threading.readerwriterlockslim(v=vs.110).aspx这给出了上面描述的确切行为
private Dictionary<string, BoneKeyFrameCollection> dict =
new Dictionary<string, BoneKeyFrameCollection>();
private ReaderWriterLockSlim dictLock = new ReaderWriterLockSlim();
public BoneKeyFrameCollection this[string boneName]
{
get
{
try
{
dictLock.EnterReadLock();
return dict[boneName];
}
finally
{
dictLock.ExitReadLock();
}
}
}
public void UpdateBone(string boneName, BoneKeyFrameCollection col)
{
try
{
dictLock.EnterWriteLock();
dict[boneName] = col;
}
finally
{
dictLock.ExitWriteLock();
}
}
或更换你的Dictionary<string, BoneKeyFrameCollection>
with a ConcurrentDictionary<string, BoneKeyFrameCollection> https://msdn.microsoft.com/en-us/library/dd287191(v=vs.110).aspx
private ConcurrentDictionary<string, BoneKeyFrameCollection> dict =
new ConcurrentDictionary<string, BoneKeyFrameCollection>();
public BoneKeyFrameCollection this[string boneName]
{
get
{
return dict[boneName];
}
}
public void UpdateBone(string boneName, BoneKeyFrameCollection col)
{
dict[boneName] = col;
}
UPDATE:我真的不明白你所显示的代码是如何导致这种情况的。这是源代码 https://referencesource.microsoft.com/#mscorlib/system/collections/generic/dictionary.cs,bcd13bb775d408f1对于导致它被抛出的函数。
private int FindEntry(TKey key) {
if( key == null) {
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
}
if (buckets != null) {
int hashCode = comparer.GetHashCode(key) & 0x7FFFFFFF;
for (int i = buckets[hashCode % buckets.Length]; i >= 0; i = entries[i].next) {
if (entries[i].hashCode == hashCode && comparer.Equals(entries[i].key, key)) return i;
}
}
return -1;
}
该代码抛出的唯一方法ArgumentOutOfRangeException
是如果您尝试在中索引非法记录buckets
or entries
.
因为你的钥匙是string
并且字符串是不可变的,我们可以排除hashcode
将键放入字典后更改的键的值。剩下的就是一个buckets[hashCode % buckets.Length]
打电话和几个entries[i]
calls.
唯一的办法buckets[hashCode % buckets.Length]
可能会失败的是如果buckets
之间被替换为buckets.Length
属性调用和this[int index]
索引器调用。唯一一次buckets
被替换的时候Resize https://referencesource.microsoft.com/#mscorlib/system/collections/generic/dictionary.cs,3b9a0882313262cd,被内部调用Insert https://referencesource.microsoft.com/#mscorlib/system/collections/generic/dictionary.cs,fd1acf96113fbda9, Initialize
由构造函数调用/第一次调用Insert
,或致电OnDeserialization
.
唯一的地方Insert
被调用的是 setterthis[TKey key]
, 公众Add
功能,以及内部OnDeserialization
。唯一的办法是buckets
要替换的是,如果我们同时调用列出的三个函数之一FindEntry
期间调用发生在另一个线程上buckets[hashCode % buckets.Length]
call.
唯一能让我们变得糟糕的方法entries[i]
调用是如果entries
被我们换掉(遵循与buckets
)或者我们得到一个不好的值i
。获得不良价值的唯一方法i
is if entries[i].next
返回一个坏值。获得不良价值的唯一方法entries[i].next
是在期间进行并发操作Insert
, Resize
, or Remove
.
我唯一能想到的就是要么出问题了OnDeserialization
调用,并且在反序列化之前您有错误的数据,或者有更多代码需要处理AnimationChannelCollection
这会影响您没有向我们展示的字典。