够用的 C# 与 Unity 序列化
你不需要从变量、循环开始重学编程。先区分三种东西:纯 C# 数据与规则、Unity 组件、编辑器序列化出来的配置。 三者用同一种语言,却有不同的创建和生命周期。
纯规则可以像后端业务代码一样写
合成判断不必继承 MonoBehaviour。下面是独立纯 C# 类,不依赖 Unity,最高等级由调用方提供:
public static class MergePolicy
{
public static bool CanMerge(int source, int target, int maxLevel)
{
return source > 0 && source == target && source < maxLevel;
}
}
这种规则容易测试,也容易向 AI 解释。Unity 组件负责把输入传给它,把结果显示出来。MonoBehaviour 组件由 Unity 管理,不要用普通 new 把它当独立业务对象创建;运行时添加组件使用相应的组件接口。
Unity 序列化不是任意 .NET 对象序列化
using UnityEngine;
public sealed class ScoreSettings : MonoBehaviour
{
[SerializeField] private int pointsPerMerge = 10;
public int PointsPerMerge => pointsPerMerge;
}
这是完整教学组件。Inspector 能配置 pointsPerMerge,调用方通过只读属性获取。修改代码中的字段初始值,已存在的组件不一定跟着改变,因为场景或 Prefab 已经保存了自己的序列化值。
常规 Unity 序列化以符合条件的字段为主,不能假设所有属性、字典、泛型容器都能自动显示和保存。复杂引用可涉及 SerializeReference 等机制,入门阶段先使用明确、简单、可检查的数据结构。
ScriptableObject 适合配置资产,例如等级表、物品图片和音效参数。它不是天然的数据库,也不会因为你改了运行时字段,就自动完成跨设备存档。
事件要和生命周期配对
// 组件方法片段:假定 scoreModel 在启用前已经设置。
private void OnEnable() => scoreModel.Changed += RefreshScore;
private void OnDisable() => scoreModel.Changed -= RefreshScore;
这与后端的订阅清理很相似。若发布者比订阅者活得久,忘记注销可能留下无效引用或重复刷新。匿名 lambda 在需要注销时容易失去原来的委托引用,应先明确订阅寿命。
把业务字段设成 static 可以快速访问,但会隐藏依赖,还可能受到编辑器域重载设置的影响。不要把“编辑器里第二次运行异常”一律归结为平台 bug,先检查静态状态是否重置。
AOT、反射与裁剪
后端常见的运行时扫描、动态生成代码和复杂反射框架,在 IL2CPP / AOT 构建中需要额外检查。编辑器可以运行,不代表最终构建保留了所有反射目标。
当序列化器或反射注册在发布版失效时,检查裁剪设置、Preserve、link.xml 和平台限制。不要第一反应就关闭所有优化;先确定真正被错误移除的类型和成员。
对 AI 的要求
请说明代码是独立纯 C#、完整 MonoBehaviour,还是依赖现有类的片段。列出所需命名空间、包和最低概念版本。涉及反射或动态代码时,解释 IL2CPP/AOT 与裁剪影响。