Dictionary drawer hides serializable fields in subclass

Issue #765 new
Tim Conkling created an issue
  • I have my own custom SerializableDictionary implementation, and Odin helpfully displays a custom inspector for it.
  • I have a subclass of this dictionary type that contains additional serializable fields. Odin’s inspector does not show the additional serializable fields; I can’t see or edit them.
  • I’m not using SerializableScriptableObject or SerializableMonoBehavior

Here’s example code that reproduces the issue:

[Serializable]
public class EnumValueConfig : SerializableDictionary<string, int> {
    [SerializeField]
    public int iDoNotAppearInTheInspector;
}

public class EnumTestConfig : ScriptableObject {
    public EnumValueConfig values;
}

Here’s what my EnumTestConfig looks like in the inspector (iDoNotAppearInTheInspector should be part of the values member, but it’s not):

And my SerializableDictionary implementation, which is very standard, looks like this:

abstract public class SerializableDictionary<TKey, TValue> :
    IDictionary<TKey, TValue>, ISerializationCallbackReceiver {

    [SerializeField]
    private List<TKey> _keys = new List<TKey>();

    [SerializeField]
    private List<TValue> _values = new List<TValue>();

    [NonSerialized]
    private Dictionary<TKey, TValue> _dict = new Dictionary<TKey, TValue>();

#region ISerializationCallbackReceiver

    virtual public void OnAfterDeserialize () {
        var c = this._keys.Count;
        this._dict = new Dictionary<TKey, TValue>(c);
        for (int ii = 0; ii < c; ii++) {
            this._dict[this._keys[ii]] = this._values[ii];
        }

        this._keys.Clear();
        this._values.Clear();
    }

    virtual public void OnBeforeSerialize () {
        this._keys.Clear();
        this._values.Clear();

        using var e = this._dict.GetEnumerator();
        while (e.MoveNext()) {
            var kvp = e.Current;
            this._keys.Add(kvp.Key);
            this._values.Add(kvp.Value);
        }
    }

#endregion

#region IDictionary<TKey, TValue>

    public int Count => this._dict.Count;

    public bool IsReadOnly {
        get {
            ICollection<KeyValuePair<TKey, TValue>> coll = this._dict;
            return coll.IsReadOnly;
        }
    }

    public void Add (KeyValuePair<TKey, TValue> item) => this._dict.Add(item.Key, item.Value);

    public void Clear () => this._dict.Clear();

    public bool Contains (KeyValuePair<TKey, TValue> item) {
        ICollection<KeyValuePair<TKey, TValue>> coll = this._dict;
        return coll.Contains(item);
    }

    public void CopyTo (KeyValuePair<TKey, TValue>[] array, int arrayIndex) {
        ICollection<KeyValuePair<TKey, TValue>> coll = this._dict;
        coll.CopyTo(array, arrayIndex);
    }

    public bool Remove (KeyValuePair<TKey, TValue> item) {
        ICollection<KeyValuePair<TKey, TValue>> coll = this._dict;
        return coll.Remove(item);
    }

    public TValue this [TKey key] {
        get => this._dict[key];
        set => this._dict[key] = value;
    }

    public ICollection<TKey> Keys => this._dict.Keys;

    public ICollection<TValue> Values => this._dict.Values;

    public bool ContainsKey (TKey key) => this._dict.ContainsKey(key);

    public void Add (TKey key, TValue value) => this._dict.Add(key, value);

    public bool Remove (TKey key) => this._dict.Remove(key);

    public bool TryGetValue (TKey key, out TValue value) => this._dict.TryGetValue(key, out value);

    public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator () => this._dict.GetEnumerator();

    IEnumerator IEnumerable.GetEnumerator () => this._dict.GetEnumerator();

#endregion
}

Environment info:

  • Unity 2020.3.0 LTS (the latest as of today)
  • Odin Inspector 3.0.4.0
  • Odin’s Editor-Only mode is enabled
  • macOS Big Sur 11.2.3

Comments (1)

  1. Log in to comment