MonoBehaviour container with generic type

I’m trying to make a Monobehaviour container that holds a instance of a custom serialized class.
I’d like to keep the instance generic so that i can use it for all my custom serialized classes.
but keep running into to errors…
easiest way would be to keep the MonoBehaviour generic but thats doesn’t seem to be supported.
tried a custom Generic class but seems that i have to give it a type in the monobehaviour so no use there.
tried same with an interface and some other things but i keep hitting a wall.
any way of doing this right?

public class GenericType<T>
{
    public T instance;

    public void SetInstance<T>(T reference)
    {
        instance = (T)reference;
    }
}
using UnityEngine;
using System.Collections;

public class Container : MonoBehaviour
{
    public GenericType gType; //asking for a type

    public T GetInstance<T>()
    {
        return gType.instance;
    }

}

You’re not passing T to your container anywhere

public class Container<T> : MonoBehaviour
{
    public GenericType<T> gType;

    public T GetInstance()
    {
        return gType.instance;
    }
}

Also note that the cast to T in your SetInstance is unnecessary.

yes but that was my first problem… you can’t set monobehaviour as generic :frowning:

That’s true. You can simply have your generic container class maintain a reference to some MonoBehaviour in that case.

well i have a CharacterCreator that spits out Enemies, Players and Friendlies each having a custom serialized non monobehaviour class instance.
I’d like the CharacterCreator to attach a monobehaviour container to the GameObject with a reference to this instance…
the script below would be a great way to do it, if monobehaviour would allow generics. sadly enough i can’t seem to find an easy workaround :-s

using UnityEngine;
using System.Collections;

public class Container<T> : MonoBehaviour
{
    public T instance;

    public T GetInstance<T>()
    {
        return instance;
    }

    public void SetInstance<T>(T reference)
    {
        instance = reference;
    }

}

You could do something like this

public class Container<T, M> where T : ScriptableObject where M : MonoBehaviour
{
    public T Data { get; set; }
    public M Script { get; set; }

    public Container()
   {
        GameObject g = new GameObject();
        Script = g.AddComponent<M>();
   }
}

ok i tried it like this:

using UnityEngine;
using System.Collections;

public class Container<T, M> where T: Character where M : MonoBehaviour
{
    public T Data { get; set; }
    public M Script { get; set; }
  
    public Container(T d, M s)
    {
        GameObject g = d.characterObject;
        Script = g.AddComponent<M>();
    }

}

and trying to call it like this:

Player p = new Player(characterObject,characterName,walkSpeed,damage,health,abilityList,ability);
            Container<Player, Container> c = new Container<Player, Container>(ref p, ref c);

and for some reason i keep getting :

Using the generic type `Container<T,M>' requires `2' type argument(s)

also i don’t quite see how i would have a monobehaviour container script that has acces to the Data instance?

Why are you explicitly passing reference types by reference? Also - you’re trying to pass c as an argument in its own constructor.Which - aside from making no sense - doesn’t fit the constraint on M (it’s not a MonoBehaviour)

even if i remove all that and just use this:

public class Container<T, M> : MonoBehaviour where T: Character where M : MonoBehaviour
{
    public T Data { get; set; }
    public M Script { get; set; }
   
//    public Container(T d, M s)
//    {
//        GameObject g = d.characterObject;
//        Script = g.AddComponent<M>();
//    }

}

and try to make a new instance of container:

            Container<Player, Container> c = new Container<Player, Container>();

it keeps saying :

Using the generic type `Container<T,M>' requires `2' type argument(s)

When you specify Container as M you’re not giving it T and M.

Why are you trying to pass Container as a parameter of Container? My suggestion was to have Script (M) be a separate MonoBehaviour derived class that does your game logic, not for Container to do both.

ah ok is see… well i wanted the Container to have the reference to a Character derived class instance like Player…
guess I’ll just skip it being generic… :frowning:

You can do that

public class Container<T> where T : Character
{
    public T Instance { get; private set; }

    public Container(T instance)
    {
        this.Instance = instance;
    }
}
Player player = new Player();
Container<Player> container = new Container<Player>(player);

ah and for Container to be a MonoBehaviour :wink:
to bad MonoBehaviour has some restriction towards basic coding concepts… I prefer handling Objects in code more than the use of components. Or maybe i just don’t see the power of MonoBehaviours…

MonoBehaviours can be generic, you just have to inherit from an actual concrete type before you can attach it to anything or see it in the editor (how else would the editor know what “T” is supposed to be?) Like this:

public class Container<T> : MonoBehaviour
public class Player : Container<Player>
2 Likes

I actually do something similar to allow my level buttons to share the same level loading functionality, even though there are many mission types:

public class MissionGeneric<T> : MonoBehaviour  where T : MissionBase {

    [SerializeField]
    public T Mission;

    protected Button mButton;

    // Use this for initialization
    void Start () {
        mButton = GetComponent<Button>();
        mButton.onClick.AddListener(OnClick);
    }

  
    public void OnClick()
    {
        GameStateManager.TheMission = Mission;
        Application.LoadLevel(Mission.LevelToLoad);
    }

This is my generic select level button, as you can see it just loads the level using the mission information supplied in T - which will 100% be from a MissionBase derived class.

For my many types of missions - i just have empty MonoBehaviours -

public class SurviveMissionButton : MissionGeneric<SurviveMission> {

  
}

This allows me to edit the mission type specific parameters in the editor and not have to worry about setting up the level loading code each time I add a new mission type.