Unity中ScriptableObject实例加入HashSet异常问题求助
问题原因与解决方案
这个问题的核心在于Unity对ScriptableObject实例的序列化/加载机制,直接导致你的构造函数逻辑没有在首次打开项目时被触发:
为什么首次打开Unity不生效?
Unity的ScriptableObject属于序列化资产,当你首次打开项目时,Unity会直接从磁盘上的.asset序列化文件中重建对象实例——这个过程不会调用C#的构造函数,它跳过了构造阶段,直接通过反序列化填充字段数据。这就导致Record.AddToMyHashSet(this)代码根本没执行,HashSet里自然没有这些实例。
为什么修改实例后恢复正常?
当你修改任意一个MyClassToInstantiate实例并保存时,Unity会重新序列化这个资产。此时Unity会重新创建该实例的对象(触发构造函数),再把修改后的字段数据序列化进去,这时候你的添加逻辑就被执行了,实例被加入HashSet。后续其他实例如果被编辑或者重新加载,也会触发同样的流程,所以功能看起来恢复了。
正确的实现方式
改用Unity的生命周期函数OnEnable()代替构造函数,这个函数会在ScriptableObject实例被加载到内存、或者从禁用状态切换到启用状态时一定会被调用,不管是首次加载还是后续编辑:
无需改动的Record类
public static class Record { private static HashSet<MyClassToInstantiate> MyHashSet = new HashSet<MyClassToInstantiate>(); public static void AddToMyHashSet(MyClassToInstantiate obj) { MyHashSet.Add(obj); } }
修改后的MyClassToInstantiate类
[CreateAssetMenu(menuName = "X")] public class MyClassToInstantiate : ScriptableObject { [SerializeField] string someRandomData1; [SerializeField] int someRandomData2; private void OnEnable() { Record.AddToMyHashSet(this); } }
额外注意事项
- HashSet自带去重特性,所以即使
OnEnable()被多次调用(比如实例被禁用再启用),也不会重复添加同一个实例。 - 如果后续需要从HashSet中移除实例,可以对应使用
OnDisable()生命周期函数,避免内存泄漏。
内容的提问来源于stack exchange,提问作者user12848525
相关产品推荐
相关产品推荐

