【解决】SerializedObjectNotCreatableException: Object at index 0 is null

开发平台:Unity
编程平台:Visual Studio 2017以上
使用语言:C#

问题描述

  SerializedObjectNotCreatableException: Object at index 0 is null
在这里插入图片描述

问题剖析

问题情况一:

  • 该问题报错以为程序序列化过程中出现空值无法处理与赋值造成的。
    具体案例如下:
[Tooltip("X轴向最大数")] private int maxXCount = 64;
[Tooltip("X轴向文本内容")] public static string xCount;

private void OnGUI()
{
    xCount = EditorGUILayout.TextField("X轴大小", xCount);
    this.maxXCount = Convert.ToInt32(xCount);
	...
}

  这是一个拓展编辑器脚本的部分代码内容。其中EditorGUILayout.TextField(Title, String)用于在EditorWindow上绘制文本输入框。【可参考继承Monobehaviourpublic string str;Inspector下的公开】。脚本经历一下步骤:

  • 建立 TextField 窗口
  • 将 TextFiled 文本内容转换为 Int 数据类型并存储于maxXCount

  值得注意的是,OnGUI()是固定时间刷新EditorWindow上的数值。在初次打开EditorWindow面板时,TextField 窗口内的数据时为空(string.Empyty),对这种数据无法使用Convert.ToInt32()进行转换。


问题情况二:

这是通过System.Reflection反射获取的UnityEditor关于Transform组件的内容的程序段,目的在于修改/拓展原生Transform组件信息。

private void OnEnable()
{
      _Editor = CreateEditor(target, Assembly.GetAssembly(typeof(Editor)).GetType("UnityEditor.TransformInspector", false));
}

【错误】其中关于 GetAssembly().GetType()中的flase为禁用 throw On Error,即抛出异常问题。很神奇/幸运 的是这类异常报错有时候并不影响工具的运行,对整个项目不会产生坏影响。对这类由Unity底层设计出现的错误,仅设置flase即可规避问题


【推测】根据Unity生命周期,Editor的激活调用在OnReset。而OnInspectorGUI()位于OnReset - OnEnable之后,然后反复调用OnInspectorGUI。在调用扩展编辑器上仅出现一次关于此类的报错。但出现一个问题 OnInspectorGUI结束后再次重复调用。唯一需要确认的时CreatSerializedObject()方法是如何?


【更新】Editor.CreateEditor()用于创建自定义编辑器扩展。其解释需要TargetType两个参数。

  • Target:源于继承的Editor提供。
  • Type:通过反射获取。而正是因为这个参数导致 SerializedObject Not CreatableException 的最终原因

  在Editor.CreateEditor()方法中,解释无指明Editor Type类型情况下,返回为Editor对象为NULL。查阅反射文章,对电脑性能要求极高,同时开销极大。则是否可以理解当执行下列代码段:

Assembly.GetAssembly(typeof(Editor)).GetType("UnityEditor.TransformInspector", false)

  获取Transform Type类型这一过程在极短的计算机时间内并没有完成对Type类型的赋值。于是,在每一次的切换Inspector窗口所对应的对象,其Inspector会销毁与创建新的组件对象。即使出现此类报错,也仅是偶然或一段时间。但组件扩展依旧正常运行。

  原理可参考UnityWebRequest,直接访问服务器,可能出现【正在连接中】,而非【连接成功】。所以搭配协程IEnumerator进行Yeild return request.SendWebRequest();直到确认到服务器连接后进行。

解决方案:

一、直接解决(根据实际逻辑情况处理,不一定有效解决)

  检查代码是否出现类似赋值于转置情况。预先赋值。例如:在 xCount = EditorGUILayout.TextField("X轴大小", xCount);前添加 xCount = maxXCount.ToString();进行赋值。

二、替换代码逻辑思路(同上)

  修改EditorGUILayout.TextField(Title, String)EditorGUILayout.TextField(String)或如下:

this.maxXCount = Convert.ToInt32(GUILayout.TextField(this.maxXCount.ToString()));

备注:该方法在EditorWindow上可使用,但无法添加文本标题。仅使用GUILayout.Label(Title)来完成排版。对排版界面上友强迫性的人不会很友好。

三、关于问题二的解决方法【更新】

  1. 使用类同IEnumerator的优先获取Type,直到反射过程完成后,再进行创建Editor
    注意:因为是面向Editor模式下的编辑器扩展,据笔者理解情报Editor模式下无法使用协程。
    弊端:受限制计算机性能差异,每次打开Inspector窗口,会不稳定的出现Transform组件(扩展版)。
  2. 使用DrawDefaultInspector()替代base.OnInspectorGUI();。扩展Transform组件并不对原组件进行修改重设计。该方法适用于基于原组件界面基础上添加额外的Button等小部件。因而在Awake/OnEnable阶段的Editor创建及相关属性可删除(未使用)。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码

)">
< <上一篇

)">
下一篇>>