You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 19:32:59