2016-03-24 22 views
4

更新:这是来自统一的确认错误,它已被归档。统一序列化字典`索引超出范围`后12项

我已经创建了一个泛型序列化字典和一个特定的int:Object。

using UnityEngine; 
using System.Collections; 
using System.Collections.Generic; 
using UnityEditor; 

/// <summary> 
/// Is what it sounds like 
/// </summary> 
[System.Serializable] 
public class SerializableDictionary<TKey,TValue> : Dictionary<TKey,TValue>, ISerializationCallbackReceiver 
{ 
    [SerializeField] 
    protected List<TKey> keys = new List<TKey>(); 

    [SerializeField] 
    protected List<TValue> values = new List<TValue>(); 

    //Save the dictionary to lists 
    public void OnBeforeSerialize() 
    { 
    keys.Clear(); 
    values.Clear(); 
    foreach(KeyValuePair<TKey,TValue> pair in this) 
    { 
     keys.Add(pair.Key); 
     values.Add(pair.Value); 
    } 
    } 

    //Load the dictionary from lists 
    public void OnAfterDeserialize() 
    { 
    this.Clear(); 

    if(keys.Count != values.Count) 
    { 
     throw new System.Exception(string.Format("there are {0} keys and {1} values after deserialization. Make sure that both key and value types are serializable.")); 
    } 

    for(int i = 0; i<keys.Count; i++) 
    { 
     this.Add(keys[i], values[i]); 
    } 
    } 
} 

[System.Serializable] 
public class DictionaryOfStringAndInt : SerializableDictionary<string, int> { } 

[System.Serializable] 
public class DictionaryOfIntAndSerializableObject : SerializableDictionary<int, ScriptableObject> 
{ 
} 

但是编译器去疯狂与错误

IndexOutOfRangeException: Array index is out of range. System.Collections.Generic.Dictionary`2+Enumerator[System.Int32,UnityEngine.ScriptableObject].MoveNext ()

出于某种原因,这条线

foreach(KeyValuePair<TKey,TValue> pair in this)

抛出的错误但只有在我DictionaryOfIntAndSerializableObject超过12级的对象。这完全让我感到困惑。

你能想到为什么这个DictionaryOfIntAndSerializableObject在12个项目后抛出一个超出范围的异常吗?

更新这个职位有相同的问题:http://forum.unity3d.com/threads/serializeable-dictionary-exceptions-after-code-change.319285/

进一步解释

我有对我的所有的模型(类型)数据的数据库游戏物体。而我正在做的是将CSV文件解析为存储在数据库GameObject中的ScriptableObjects。这样我的数据库在运行时编译一次,我可以在运行时和编辑器中自由访问它。这个数据库对象是什么有DictionaryOfIntAndSerializableObject对象。每桌有一个(所以我有一个用于武器,盔甲等)。

这是基础类我所有的脚本化的对象(即获取存储在词典中的值):

public class M_Card : ScriptableObject 

{ 

    public E_CardTypes cardTypeID; 

    public int rankID; 

    public int rarityID; 

    public int qualityID; 

    public int editionID; 

    public Sprite sprite; 

public M_Card() 
{ 
    cardTypeID     = 0; 
    rankID      = 0; 
    qualityID     = 0; 
    sprite = null; 
} 

} 

这里是代码中(从CSV解析行之后)我把M_Card的实例到字典:

private void LoadActionCards() 
{ 
    List<Dictionary<string, object>> listData = CSVReader.Read("Actions"); 

    for (var i = 0; i < listData.Count; i++) 
    { 
     Dictionary<string, object> data = listData[i]; 

     string name = (string)data["Name"]; 
     M_ActionCard card = ScriptableObjectCreator.createActionCard(name); 

     int cardTypeID = (int)data["CardTypeID"]; 
     card.cardTypeID = (E_CardTypes)cardTypeID; 

     AssignActionCardValues(card, data); 

     Database.ACTION_CARD_LIST.Add(card); 

     // THIS IS WHERE I MAP THE TYPEID TO THE M_CARD OBJECT 
     // THIS IS WHERE THE OBJECT IS ADDED TO THE DICTIONARY 
     Database.ACTION_CARD_MAP[card.ID] = card; 
    } 
    } 

所以现在我有4个表中的数据(武器,头盔,铠甲,班)的。但是,如果这些表中有超过12个项目,我会在第13个项目中得到100%的错误。我仍在调查,但继承人如何将密钥添加到字典中。

请注意,M_HelmetCard与M_ActionCard相同,它们都只是M_Card的空子类。

这里有一些图片添加更多一点证明。首先,我有全部16个头盔。出现错误 enter image description here

然后在这里,我只做了12个,错误消失了。 enter image description here

任何列表超过12个错误。实际的项目并不重要(所以它不像特定的第13项已损坏,13项相同的项目仍然会导致此错误)。

此刻非常困惑。

(我想也许问题是我有一个Sprite类被序列化,数据太多,但当我摆脱它时,问题仍然存在)。

更新这里是一个示例项目的链接有这个问题(一切都无关)。 https://www.mediafire.com/?axxn3u823cm7c59

产生错误: 请按下erairachy中的database对象,然后单击Update Database按钮。

然后只要点击播放,你会看到错误。

然后,如果你想看看它的第13项,打开头盔CSV文件(\Assets\Resources\ExcelData),并删除第13项。然后再次更新数据库。然后点击播放。错误将会消失!

这是一个主要的WTF:?

+0

的热心帮助生成我的解决办法'但是编译器去疯狂与错误...'你的意思是你编译时错误?或者你在运行时得到这个? – dotnetom

+0

对我来说可疑...'int value = keys [Random.Range(0,keys.Count)];'尤其是'Random'部分... – Ian

+0

也不担心RandomID(它甚至没有使用atm: P)。 – Aggressor

回答

2

我偶然发现了同样的问题。看起来Unity的序列化有时会破坏序列化字典的内部,因此无法添加额外的值。

在我的情况下,我通过在SerializableDictionary上实现IDictionary接口并将其功能委托给私有的Dictionary对象来解决这些错误,该对象未被Unity序列化触及。

下面是使用Visual Studio

using UnityEngine; 
using System.Collections.Generic; 
using System.Collections; 

[System.Serializable] 
public class SerializableDictionary<TKey, TValue> : IDictionary<TKey, TValue>, ISerializationCallbackReceiver 
{ 
    [SerializeField] 
    private List<TKey> keys = new List<TKey>(); 

    [SerializeField] 
    private List<TValue> values = new List<TValue>(); 

    private Dictionary<TKey, TValue> dictionary = new Dictionary<TKey, TValue>(); 

    public ICollection<TKey> Keys 
    { 
     get 
     { 
      return ((IDictionary<TKey, TValue>)dictionary).Keys; 
     } 
    } 

    public ICollection<TValue> Values 
    { 
     get 
     { 
      return ((IDictionary<TKey, TValue>)dictionary).Values; 
     } 
    } 

    public int Count 
    { 
     get 
     { 
      return ((IDictionary<TKey, TValue>)dictionary).Count; 
     } 
    } 

    public bool IsReadOnly 
    { 
     get 
     { 
      return ((IDictionary<TKey, TValue>)dictionary).IsReadOnly; 
     } 
    } 

    public TValue this[TKey key] 
    { 
     get 
     { 
      return ((IDictionary<TKey, TValue>)dictionary)[key]; 
     } 

     set 
     { 
      ((IDictionary<TKey, TValue>)dictionary)[key] = value; 
     } 
    } 

    public void OnBeforeSerialize() 
    { 
     keys.Clear(); 
     values.Clear(); 
     foreach (KeyValuePair<TKey, TValue> pair in this) 
     { 
      keys.Add(pair.Key); 
      values.Add(pair.Value); 
     } 
    } 

    public void OnAfterDeserialize() 
    { 
     dictionary = new Dictionary<TKey, TValue>(); 

     if (keys.Count != values.Count) 
     { 
      throw new System.Exception(string.Format("there are {0} keys and {1} values after deserialization. Make sure that both key and value types are serializable.", keys.Count, values.Count)); 
     } 

     for (int i = 0; i < keys.Count; i++) 
     { 
      Add(keys[i], values[i]); 
     } 
    } 

    public void Add(TKey key, TValue value) 
    { 
     ((IDictionary<TKey, TValue>)dictionary).Add(key, value); 
    } 

    public bool ContainsKey(TKey key) 
    { 
     return ((IDictionary<TKey, TValue>)dictionary).ContainsKey(key); 
    } 

    public bool Remove(TKey key) 
    { 
     return ((IDictionary<TKey, TValue>)dictionary).Remove(key); 
    } 

    public bool TryGetValue(TKey key, out TValue value) 
    { 
     return ((IDictionary<TKey, TValue>)dictionary).TryGetValue(key, out value); 
    } 

    public void Add(KeyValuePair<TKey, TValue> item) 
    { 
     ((IDictionary<TKey, TValue>)dictionary).Add(item); 
    } 

    public void Clear() 
    { 
     ((IDictionary<TKey, TValue>)dictionary).Clear(); 
    } 

    public bool Contains(KeyValuePair<TKey, TValue> item) 
    { 
     return ((IDictionary<TKey, TValue>)dictionary).Contains(item); 
    } 

    public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) 
    { 
     ((IDictionary<TKey, TValue>)dictionary).CopyTo(array, arrayIndex); 
    } 

    public bool Remove(KeyValuePair<TKey, TValue> item) 
    { 
     return ((IDictionary<TKey, TValue>)dictionary).Remove(item); 
    } 

    public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() 
    { 
     return ((IDictionary<TKey, TValue>)dictionary).GetEnumerator(); 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return ((IDictionary<TKey, TValue>)dictionary).GetEnumerator(); 
    } 
} 
+0

我想出了一个不同的解决方案,但感谢您的分享。如果有需要,我会重新审视你的所在! – Aggressor