Retrieving array size but no array was provided

Hello,

I’m trying to do a custom PropertyDrawer for a custom class with a List. To format the list i use the ReordorableList classe provided by Unity.

The problème is when i try to initialise the list, i got the error : Retrieving array size but no array was provided.

Here my PropertyDrawer :

using UnityEngine;
using UnityEditor;
using UnityEditorInternal;

[CustomPropertyDrawer(typeof(SpellsEffectsList))]
public  class Drawer_SpellsEffectsList : PropertyDrawer {
    //_____ PROTECTED PROPERTIES ________________________________________________
    protected ReorderableList _reorderableList;
    protected SerializedProperty _serializedList;
    protected string _headerText = "";



    //_____ CONSTRUCTOR _________________________________________________________
    ~Drawer_SpellsEffectsList () {       
        // Delete Callback to make sure we don't get memory leaks etc.
        this._reorderableList.drawHeaderCallback -= this.DrawHeader;
        this._reorderableList.drawElementCallback -= this.DrawElement;

        this._reorderableList.onAddCallback -= this.AddItem;
        this._reorderableList.onRemoveCallback -= this.RemoveItem;
    }





    //_____ TRIGGER _____________________________________________________________
    public override void OnGUI (Rect position, SerializedProperty property, GUIContent label){
        this._reorderableList = new ReorderableList(property.serializedObject, property, true, true, true, true);
            // => this is where the error occured : Input elements should be an Array SerializedProperty
       
        // Add listeners to draw events
        this._reorderableList.drawHeaderCallback += this.DrawHeader;
        this._reorderableList.drawElementCallback += this.DrawElement;

        this._reorderableList.onAddCallback += this.AddItem;
        this._reorderableList.onRemoveCallback += this.RemoveItem;

        // Add header
        this._headerText = label.text;

        // Override logic works on the entire property
        EditorGUI.BeginProperty(position, label, property);
       
        this._reorderableList.DoLayoutList();

        EditorGUI.EndProperty();
       
        // Apply changes to the serializedProperty
        property.serializedObject.ApplyModifiedProperties();
    }



    //_____ METHODES ____________________________________________________________   
    /* -------------------------------------------------------------------------------------------------------------------------
     * Draws one element of the list
     * ------------------------------------------------------------------------------------------------------------------------- */
    protected void  DrawElement (Rect rect, int index, bool active, bool focused) {
        SerializedProperty item = this._serializedList.GetArrayElementAtIndex(index);
        SerializedProperty element_Id = item.FindPropertyRelative("_id");

        EditorGUI.BeginChangeCheck();
        EditorGUI.PropertyField(rect, element_Id);
        if (EditorGUI.EndChangeCheck()){
            // Set the item as modified and add the modification in the undo action list
            Undo.RecordObject(this._serializedList.serializedObject.targetObject, "Cancel item's modification on " + this._serializedList.GetType().ToString() + " reorderable list");
        }   
    }
   
   
    /* -------------------------------------------------------------------------------------------------------------------------
     * Draws the header of the list
     * ------------------------------------------------------------------------------------------------------------------------- */
    private void DrawHeader(Rect rect){
        GUI.Label(rect, this._headerText);
    }
         
    /* -------------------------------------------------------------------------------------------------------------------------
     * Add an item in the list
     * ------------------------------------------------------------------------------------------------------------------------- */
     private void AddItem(ReorderableList list){
        this._serializedList.InsertArrayElementAtIndex(list.index);

        // Set the list as modified and add the modification in the undo action list
        Undo.RecordObject(this._serializedList.serializedObject.targetObject, "Cancel Add item on " + this._serializedList.GetType().ToString() + " reorderable list");
     }

    /* -------------------------------------------------------------------------------------------------------------------------
     * Delete an item of the list
     * ------------------------------------------------------------------------------------------------------------------------- */
     private void RemoveItem(ReorderableList list) {
        this._serializedList.DeleteArrayElementAtIndex(list.index);
       
        // Set the list as modified and add the modification in the undo action list
        Undo.RecordObject(this._serializedList.serializedObject.targetObject, "Cancel Remove item on " + this._serializedList.GetType().ToString() + " reorderable list");
     }
}

Here my SpellsEffectsList :

using System.Collections.Generic;
using System;

[Serializable]
public class SpellsEffectsList : List<SpellEffect> {
    // Only some methodes here ...
}

Here how the list is declared :

[SerializeField]
    private SpellsEffectsList    _spellsEffects    = new SpellsEffectsList();

Here how the the propertyDrawer is called from a custom Editor :

public override void OnInspectorGUI () {
        // few code ...
        EditorGUILayout.PropertyField(serializedSpell.FindProperty("_spellsEffects"), true);
        // some other code ...
    }

When i’m in debug mode,I have this in Visual Studio :

I don’t understand why i have this problème.

Do you have an idea ?

Thanks for your help.

Hi @tribaleur

Is there a specific reason you are extending generic list?

public class SpellsEffectsList : List<SpellEffect> {}

Try using list with type instead, and you should get your list working (in Custom Editor):

public List<SpellEffect> list = new List<SpellEffect>();

Hi Eses,

I already tried it, but i have the message “nullReferenceException: Object reference not set to an instance of an object” in the Editor when i call the propertyDrawer .

In the custom Editor :

public override void OnInspectorGUI () {

        Spell gameObject_Spell = (Spell)target;
        if (gameObject_Spell.SpellsEffects == null) { Debug.Log("Null liste"); }
        else { Debug.Log("Not Null liste"); } // The log show me this message so the list is instanciate  ?
        SerializedObject serializedSpell = new SerializedObject(gameObject_Spell);

*** EDIT ***
SerializedProperty spl = serializedSpell.FindProperty("_spellsEffects");
// This always return Null even if the serializedSpell have the property "_spellsEffects" set.
// I tried as well with the name of the Get accessor but it still doesn't works.
// So the question is why the List can't be found by "FindProperty()" ?
*** END EDIT ***

        // ...

        EditorGUILayout.PropertyField(serializedSpell.FindProperty("_spellsEffects"), true);
        // => The error message is there !

        // ...
    }

I don’t understand why i have this error.

About the extend of the generic list : it’s to modify the Add() method and to create some news one

What I mean;

I tried this - if using just a generic list, this will find the list:

var prop = serializedObject.FindProperty("list");

And the classes look like this:

public class SpellEffects : MonoBehaviour
{
    // this will work
    public List<SpellEffect> list = new List<SpellEffect>();
}

[System.Serializable]
public class SpellEffect
{
    public string someString = "foo";
}

But if using sub class of generic list (what you were using) Unity serialized property doesn’t seem to be able to find the list… Maybe such list isn’t supported.

You can achieve similar results by using extension methods. For example:

public static class SpellEffectListExtensions
{
   public void AddEffect(this IList<SpellEffect> self, SpellEffect item)
   {
      self.Add(item);
      // Whatever else
   }
}

...

List<SpellEffect> list;
list.AddEffect(myEffect);

Hi guys,

Thanks for your help.

@eses : I tried the following to understand.

I declared 3 list :

[SerializeField]
    private SpellsEffectsList    _spellsEffects    = new SpellsEffectsList();
    [SerializeField]
    private List<SpellEffect>    _spellsEffects2    = new List<SpellEffect>();
    [SerializeField]
    private List<Object>    _objects    = new List<Object>();

In the editor i tried this :

        SerializedProperty se = serializedObject.FindProperty("_spellsEffects"); // Return a serialisedProperty but not as an array
        SerializedProperty se2 = serializedObject.FindProperty("_spellsEffects2"); // Return Null
        SerializedProperty lo = serializedObject.FindProperty("_objects"); // Return an empty List of object (isArray = true)

So it doesn’t works when the elements have the SpellEffect type.
After few test i found why … SpellEffect is an abstract class for inheritance. It’s looks like unity can’t serialise abstract class. I have to think on how to change that classe to not abstract.

Anyway, SpellsEffectsList is still not recognised as an array when List does. So i have to think on @ErrorStatz solution. Thanks for your help guys.