Generic List of type <int> not being serialized in the inspector but T as <int> is

Hello,

I’m trying to create a system using generics and scriptable objects to encapsulate the relationship between content items and the rank in which they get unlocked. I create a generic class BaseUnlockItemBase which contains a rank value and method for determining whether or not the generic type item is unlocked when given a rank. The user can simply extend this class to create new rank unlock items of different types.

I then have a generic class RankUnlockedItemContainer which also extends ScriptableObject which is supposed to serve the purpose of containing RankUnlockedItemBase and providing means of retrieving items based on rank.

Anyway, so when I extend RankUnlockedItemBase and specify the type parameter as type that can be serialized like int,string,etc, item will be serialized and visible in the inspector! However, when I extend RankUnlockedItemContainer and specify the type parameter, the list will not be serialized and shown in the inspector.

Any ideas why?

TL;DR Extentions of generic class wont serialize T as lists of ints or whatever but it’s happy to serialize T as int or whatever

public class RankUnlockedItemBase<T> : ScriptableObject
{
    [SerializeField] private int acquiredRankPoints;
    public int AcquiredRankPoints { get => acquiredRankPoints; }
    [SerializeField] private T item;
    public T Item => item;

    public bool IsUnlocked(int rankPoints)
    {
        return rankPoints > acquiredRankPoints;
    }
}

This works! item will be serialized in the inspector

public class RankUnlockedInt : RankUnlockedItemBase<int> { }
public class RankUnlockedItemContainer<T> : ScriptableObject
{
    [SerializeField] private List<RankUnlockedItemBase<T>> items;
    public List<RankUnlockedItemBase<T>> Items {get => items; }

    public List<RankUnlockedItemBase<T>> GetAllUnlockedItemsUpToRank(int rank)
    {
        List<RankUnlockedItemBase<T>> unlockedItems = new List<RankUnlockedItemBase<T>>();
        for (int i = 0; i < items.Count; i++)
        {
            if (items[i].IsUnlocked(rank))
            {
                unlockedItems.Add(items[i]);
            }
        }

        return unlockedItems;
    }
}

This doesn’t work! items IS NOT serialized in the inspector

public class RankUnlockedIntContainer : RankUnlockedItemContainer<int> {}

Solved with:

public class RankUnlockedItemContainer<TItem, TValue> : ScriptableObject where TItem : RankUnlockedItemBase<TValue>
{
    [SerializeField] private List<TItem> items;
    public List<TItem> Items {get => items; }

    public List<TItem> GetAllUnlockedItemsUpToRank(int rank)
    {
        List<TItem> unlockedItems = new List<TItem>();
        for (int i = 0; i < items.Count; i++)
        {
            if (items[i].IsUnlocked(rank))
            {
                unlockedItems.Add(items[i]);
            }
        }

        return unlockedItems;
    }
}

Unity’s built-in serializer is not terribly robust, and for some reason doesn’t like nested generic types.

You can work around this by declaring a non-generic subclass of the generic class that you actually want to use (which I think you figured out, though I didn’t 100% follow your post).