总的来说:你不应该使用BinaryFormatter anymore https://learn.microsoft.com/dotnet/standard/serialization/binaryformatter-security-guide at all!
您可以构建一个包装类来实现ISerializationCallbackReceiver https://docs.unity3d.com/ScriptReference/ISerializationCallbackReceiver.html界面。在他们的示例中,甚至有几乎与您完全相同的用例!
稍微修改一下的解决方案可能看起来像例如
[Serializable]
public class YourDictionary: Dictionary<GameObject, Vector2>, ISerializationCallbackReceiver
{
[HideInInspector][SerializeField] private List<GameObject> _keys = new List<GameObject>();
[HideInInspector][SerializeField] private List<Vector2> _values = new List<Vector2>();
public void OnBeforeSerialize()
{
_keys.Clear();
_values.Clear();
foreach (var kvp in this)
{
_keys.Add(kvp.Key);
_values.Add(kvp.Value);
}
}
public void OnAfterDeserialize()
{
Clear();
for (var i = 0; i != Math.Min(_keys.Count, _values.Count); i++)
{
Add(_keys[i], _values[i]);
}
}
}
通过这种方式,您可以保留字典及其接口的全部功能,但只需在顶部添加序列化即可。
然后在你使用的其他脚本中
[HideInInspector] public YourDictionary occupants;
并像使用它一样Dictionary<GameObject, Vector2>
(我是说Add
, Remove
, Clear
, foreach
etc).
现在它正在发挥作用。我只是使用了这个简单的测试脚本
public class NewBehaviourScript : MonoBehaviour
{
public GameObject obj;
[HideInInspector] public YourDictionary occupants;
[ContextMenu(nameof(Add))]
private void Add()
{
Vector2 vec = obj.transform.position;
occupants.Add(obj, vec);
}
[ContextMenu(nameof(Apply))]
private void Apply()
{
foreach (var kvp in occupants)
{
kvp.Key.transform.position = kvp.Value;
}
}
[ContextMenu(nameof(Remove))]
private void Remove()
{
occupants.Remove(obj);
}
}
现在可以愉快地存储、删除和应用场景中对象的位置;)
- 我首先存储 4 个物体的位置。
- 然后我将它们移到其他地方并保存场景
- 我卸载场景并创建一个新的空场景
- 我加载原始场景
-
Result点击“应用”后,所有对象都回到原位,这意味着字典已成功(反)序列化;)