Generic types in C# for a function

I was trying to create a function that returned a GameObject with a sprite, a BoxCollider2D, and some other things. I didn’t want to do it every time I make a new object because I make one a lot. I also wanted to attach a component I called BulletBehavior to the object, but BulletBehavior is abstract so I needed to specify which one I wanted to use. This code, for some reason, is not working:

public static GameObject readyObject<T>(T behavior, Sprite sprite, Vector2 scale){
		GameObject obj = new GameObject ();
		obj.tag = "Bullet";
		obj.AddComponent<SpriteRenderer>();
		obj.GetComponent<SpriteRenderer>().sprite = sprite;
		obj.AddComponent<BoxCollider2D> ().isTrigger = true;
		obj.AddComponent<T>();
		obj.transform.localScale = new Vector3(scale.x, scale.x, 1);
		return obj;
	}

The error is this: Assets/BulletBehavior.cs(11,21): error CS0309: The type T' must be convertible to UnityEngine.Component’ in order to use it as parameter T' in the generic type or method UnityEngine.GameObject.AddComponent()’

While they dropped the generic constraint for GetComponent, AddComponent still has a constraint on the generic parameter that requires the type used to be derived from “Component”. Since your generic parameter “T” has no constraints at all, one could use any type as parameter, even “int” or “string”.

So the solution is to add a generic constraint to your parameter “T”

public static GameObject readyObject<T>(T behavior, Sprite sprite, Vector2 scale) where T : Component
{
    // [...]

ps; Your method haa a parameter of type T called “behavior”, but you don’t use that inside your method. It’s not really required, at least for what your method currently does. Also you may have a typo in line 8 where you used scale.x twice. If it’s intentionally you should use a simple float instead of a Vector2.

Hi @chubit,

Instead of returning a GameObject, why don’t you make a script class that has all of your mentioned Components as attributes or fields? The gameObject could then simply be accessed by scriptInstance.gameObject. And maybe you could use an Interface instead of the abstract class? I don’t know if it is the right way and please correct me if this is a bad approach, but I think of something like this:

public static GameObject readyObject<T>(IBulletBehavior behavior, Sprite sprite, Vector2 scale){
         GameObject obj = new GameObject ();
         BulletScript sc = gameObject.AddComponent<BulletScript>( ) as BulletScript;
         sc.setBulletBehavior(behavior);
         //do other logic...
         return obj;
     }