System.Object polymorphism with array and non-array types breaks the inspector

Issue #434 resolved
Nicolás Ezcurra created an issue

Using Unity 2017.4.11f1 and Odin 2.0.5, when a field of type object, has it actual value changed while inspecting it, will break the inspector.

This behaviour occurs when the value types changes from an array type to a non array type, and vice versa.

Here is a simple component where this issue can be checked:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

using Sirenix.OdinInspector;
using System;

public class SimpleObjectFieldTest : SerializedMonoBehaviour 
{
    [SerializeField]
    public object field;


    [Button]
    public void SetInt()
    {
        field = default(int);
    }

    [Button]
    public void SetTransform()
    {
        field = transform;
    }

    [Button]
    public void SetFloatArray()
    {
        field = new float[0];
    }

    [Button]
    public void SetGameObjectArray()
    {
        field = new GameObject[0];
    }

    [Button]
    public void PrintType()
    {
        Debug.LogFormat("[ObjectFieldTest] Field type: {0}.", (field == null) ? "null" : field.GetType().ToString());
    }
}

I'm also attaching an attempt of solution using an Attribute (ObjectFieldTest, DrawAsTypeAttribute and DrawAsTypeAttributeDrawer).

Thanks for your time!

Comments (3)

  1. Tor Esa Vestergaard

    If you change values that change the "layout" of the data during the GUI loop (such as in a button press), you will get GUI layout errors. The issue can in this case be resolved by delaying the actual value change to a later time when it is "safe" to do:

    [Button]
    public void SetInt()
    
    {
        EditorApplication.delayCall += () => field = default(int);
    }
    

    Let me know if there's any other issues, or if the code above does not fix the problem at hand.

  2. Nicolás Ezcurra reporter

    I'm already trying to use the delayCall delegate, and is not working. For example, this simple script won't work either when changing some types:

    using UnityEngine;
    
    using Sirenix.OdinInspector;
    
    #if UNITY_EDITOR
    using UnityEditor;
    #endif
    
    public class ObjectFieldTest : SerializedMonoBehaviour
    {
    #if UNITY_EDITOR
        [SerializeField]
        public object field;
    
        [Button]
        public void SetInt() => EditorApplication.delayCall += () => field = default(int);
    
        [Button]
        public void SetTransform() => EditorApplication.delayCall += () => field = transform;
    
        [Button]
        public void SetFloatArray() => EditorApplication.delayCall += () => field = new float[0];
    
        [Button]
        public void SetGameObjectArray() => EditorApplication.delayCall += () => field = new GameObject[0];    
    
        [Button]
        public void Restore() => EditorApplication.delayCall += () => field = default(System.Object);    
    
        [Button]
        public void PrintType()
        {
            UnityEngine.Debug.LogFormat("[ObjectFieldTest] Field type: {0}.", (field == null) ? "null" : field.GetType().ToString());
        }
    #endif
    }
    
  3. Log in to comment