Unity 2022.3.3f1泛型Translation System序列化异常问题求助
解决Unity泛型TranslationProperty序列化问题
问题根源
Unity内置序列化系统对泛型类的支持存在限制,即便IntProp是非泛型子类,但其继承链中存在泛型抽象类TranslationProperty<T>,会直接导致序列化失效。另外,ScriptableObject作为资源对象,必须以独立Asset文件的形式存在才能被正确序列化持久化,仅在内存中创建实例无法被Unity序列化保存。
修复方案
1. 清理泛型基类的序列化标记
泛型类本身无法被Unity序列化,移除TranslationProperty<T>上的[Serializable]特性,避免序列化系统混淆。
2. 调整字段定义方式
将自动属性改为普通字段加属性封装,Unity对普通字段的序列化支持更稳定。
3. 实现ScriptableObject的Asset化创建
修改实例创建逻辑,将子类实例保存为Project中的Asset文件,而非仅在内存中生成。
4. 修正编辑器实例创建逻辑
在编辑器中创建并保存ScriptableObject Asset后再赋值给MonoBehaviour字段,确保引用可被序列化。
修改后的代码示例
基础类(TranslationProperty)
using System; using UnityEngine; [Serializable] public abstract class TranslationProperty : ScriptableObject { [SerializeField] protected string _name; public string Name => _name; public abstract void SetValue(object newValue); public abstract object GetValue(); public static T CreateInstance<T>(string assetPath, string name, string value) where T : TranslationProperty { var instance = CreateInstance<T>(); instance._name = name; instance.Init(value); #if UNITY_EDITOR UnityEditor.AssetDatabase.CreateAsset(instance, assetPath); UnityEditor.AssetDatabase.SaveAssets(); #endif return instance; } protected abstract void Init(string value); public abstract TranslationProperty Clone(); #if UNITY_EDITOR public bool Foldout = false; public abstract void OnInspector(); #endif }
泛型基类(TranslationProperty)
using UnityEngine; using System; #if UNITY_EDITOR using UnityEditor; #endif // 移除泛型类的Serializable标记 public abstract class TranslationProperty<T> : TranslationProperty { [SerializeField] protected T _value; public T Value => _value; public override object GetValue() => _value; public override void SetValue(object newValue) { if (newValue is T typedValue) _value = typedValue; } public abstract T Parse(string value); public override TranslationProperty Clone() { TranslationProperty<T> instance = (TranslationProperty<T>)GetInstance(); instance._name = _name; instance.SetValue(_value); return instance; } protected abstract TranslationProperty GetInstance(); public override string ToString() => _value.ToString(); protected override void Init(string value) => _value = Parse(value); #if UNITY_EDITOR public override void OnInspector() { EditorGUILayout.LabelField($"Property {_name}"); } #endif }
子类(IntProp)
using UnityEngine; using System; #if UNITY_EDITOR using UnityEditor; #endif [Serializable] public class IntProp : TranslationProperty<int> { public override int Parse(string value) => int.Parse(value); protected override TranslationProperty GetInstance() => CreateInstance<IntProp>(); #if UNITY_EDITOR public override void OnInspector() { EditorGUILayout.BeginHorizontal(); base.OnInspector(); _value = EditorGUILayout.IntField(_value); EditorGUILayout.EndHorizontal(); } #endif }
测试类(TestTranslation)
using UnityEngine; public class TestTranslation : MonoBehaviour { public IntProp prop; }
测试编辑器(TestTranslationEditor)
using UnityEditor; [CustomEditor(typeof(TestTranslation))] [CanEditMultipleObjects] public class TestTranslationEditor : Editor { public override void OnInspectorGUI() { TestTranslation t = (TestTranslation)target; if (t.prop == null) { string assetPath = $"Assets/IntProp_Prop1.asset"; t.prop = TranslationProperty.CreateInstance<IntProp>(assetPath, "prop1", "0"); } t.prop.OnInspector(); EditorUtility.SetDirty(t.prop); EditorUtility.SetDirty(t); } }
额外注意事项
- 所有
ScriptableObject子类实例必须保存为Asset文件,才能被Unity正确序列化持久化,退出Play模式后数据不会丢失。 - 若需运行时动态创建实例并序列化,可考虑用
JsonUtility手动序列化数据,或改用普通可序列化类存储数据,避免依赖泛型ScriptableObject的自动序列化。 - Unity序列化系统仅支持非泛型的可序列化类型,泛型类无法被自动序列化。
内容的提问来源于stack exchange,提问作者Patricio Díaz
相关产品推荐
相关产品推荐

