Agg*_*sor 5 c# serialization dictionary unity-game-engine deserialization
更新:这是 Unity 确认的错误,并且已提交。
我创建了一个通用的可序列化字典和一个用于 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>
{
}
Run Code Online (Sandbox Code Playgroud)
然而编译器因错误而变得疯狂
IndexOutOfRangeException:数组索引超出范围。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/
进一步说明
我有一个数据库 GameObject,其中保存了我的所有模型(类型)数据。我正在做的是将 CSV 文件解析为ScriptableObjects存储在数据库 GameObject 中的文件。这样我的数据库在运行时编译一次,我可以在运行时和编辑器中自由访问它。该数据库对象就是拥有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;
}
}
Run Code Online (Sandbox Code Playgroud)
下面是代码(在解析 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;
}
}
Run Code Online (Sandbox Code Playgroud)
现在我有 4 个数据表(武器、头盔、盔甲、职业)。但是,如果这些表中的任何一个包含超过 12 个项目,我会在第 13 个项目上得到 100% 的错误。我仍在调查,但这是如何将键添加到字典中的。
请注意,M_HelmetCard 与 M_ActionCard 相同,它们都只是 M_Card 的空子类。
这里有一些图片来添加更多证据。第一个我有全部 16 个头盔。出现错误

任何错误超过 12 个的列表。实际的项目并不重要(所以它不像特定的第 13 个项目已损坏,13 个相同的项目仍然会导致此错误)。
此刻非常困惑。
(我想问题可能是我有一个Sprite类正在被序列化并且数据太多,但是当我摆脱它时问题仍然存在)。
更新这里是一个存在此问题的示例项目的链接(删除了所有不相关的内容)。https://www.mediafire.com/?axxn3u823cm7c59
要产生错误:单击database层次结构中的对象,然后单击Update Database按钮。
然后点击播放,您就会看到错误。
然后,如果您想查看第 13 项,请打开 Helmets CSV 文件 ( \Assets\Resources\ExcelData),然后删除第 13 项。然后再次更新数据库。然后点击播放。错误就会消失!
这是一个重大的WTF:?
我偶然发现了同样的问题。Unity 的序列化有时会破坏序列化字典的内部结构,导致无法添加其他值。
IDictionary就我而言,我通过实现接口并将SerializableDictionary其功能委托给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();
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1954 次 |
| 最近记录: |