2016-03-24 3 views
4

更新:これはUnityの確認済みのバグであり、提出されています。Unityシリアライズされたディクショナリ「12個の項目の後にインデックスが外れる」

汎用のシリアライズ可能なディクショナリと、int:Objectの特定のディクショナリを作成しました。コンパイラが何らかの理由でエラー

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

と狂気しかし

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> 
{ 
} 

このライン

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

は、そのエラーをスローしますが、私のDictionaryOfIntAndSerializableObjectは12個のオブジェクトを超えた後にのみ。これは完全に私を困惑させる。

DictionaryOfIntAndSerializableObjectが12個の項目の後に範囲外の例外を投げている理由を考えることができますか? http://forum.unity3d.com/threads/serializeable-dictionary-exceptions-after-code-change.319285/

さらに説明

私はすべてのモデル(タイプ)のデータを保持するデータベースのゲームオブジェクトを持っている:

更新この投稿は、同じ問題を持っています。私がやっているのは、CSVファイルを構文解析してScriptableObjectsにして、データベースGameObjectの中に保存するということです。そうすれば、私のデータベースは実行時に一度コンパイルされ、実行時とエディタの両方で自由にアクセスできます。このデータベースオブジェクトは、DictionaryOfIntAndSerializableObjectオブジェクトを持つオブジェクトです。私はすべてのテーブルのために1つを持っている(私は武器、鎧などのために1つを持っている)。ここで

はすべての私のスクリプト可能なオブジェクトの基底クラス(それは辞書に値として格納されます)です:

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から行を解析した後)のコードであるI辞書に部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

ここで私はそれを作るので、エラーはなくなりました。 enter image description here

エラーが12個を超えるリスト。実際のアイテムは問題ではありません(特定の13番目のアイテムが破損しているようではなく、13個のアイテムがこのエラーを引き起こします)。

現時点では非常に困惑しています。

(私はSpriteクラスがシリアル化されていて、データが多すぎると思っていたかもしれませんが、問題が解消されても問題は解決しませんでした)

更新ここに、この問題があるサンプルプロジェクトへのリンクがあります(削除されていないものはすべて削除されています)。

https://www.mediafire.com/?axxn3u823cm7c59は、エラーを生成するには、次のheirachyでdatabaseオブジェクトをクリックしてUpdate Databaseボタンをクリックしてください 。

次に再生を押すと、エラーが表示されます。

13番目のアイテムの見方を確認するには、Helmets CSVファイル(\Assets\Resources\ExcelData)を開いて、13番目のアイテムを削除します。次に、データベースを再度更新します。その後、ヒットします。エラーはなくなります!

これは主要なWTFです:?

+0

の種類の助けを借りて生成された 'ただし、コンパイラはあなたが時エラーをコンパイルし得る意味でください' ...エラーでクレイジー行きますか?それとも、実行時にこれを手に入れますか? – dotnetom

+0

私には疑わしいと思われる... int value = keys [Random.Range(0、keys.Count)]; '特にランダムな部分... – Ian

+0

そうではありませんが、 P)。 – Aggressor

答えて

2

同じ問題が発生しました。ユニティのシリアライゼーションは、シリアライズされた辞書の内部を破壊することがあり、追加の値を追加できないようです。

私の場合はSerializableDictionaryIDictionaryインタフェースを実装し、それはユニティのシリアル化とは無縁である民間Dictionaryオブジェクトへの機能です委譲することで、これらのエラーを処分しました。ここで

が私の解決策は、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

関連する問題