Passing arguments into a constructor via AddComponent

Hi there,

I am currently learning c# and a little stuck. I am trying to call an instance of a class and pass some values into a constructor. I was able to achieve this using the usual method of:

SomeClass myclass = New SomeClass(value1,value2)

However I ran into the problem of not being able to use the keyword New in Unity. After some research it looks like there are 2 solutions to that problem. I can remove Monobehavior(which i don’t want to do) or I can use AddComponent. AddComponent is the way I want to go but I am unsure how to pass it my values. My code is below and as you can see from the comments I have tried a few things. Any advice?

if(hit.collider.tag == "Object"){
    	Debug.DrawRay(myRay.origin, myRay.direction * hit.distance, Color.red);
    	//InteractObject o = ScriptableObject.CreateInstance("InteractObject") as InteractObject;
    
    	//InteractObject instancedClass = gameObject.AddComponent<InteractObject>(true,hit.collider.gameObject.name);
    
    	//GameObject obj = hit.collider.gameObject;
    	//InteractObject script = obj.AddComponent<InteractObject>();
    
    	InteractObject o = new InteractObject(true,hit.collider.gameObject.name);

And the InteractObject class:

public class InteractObject : MonoBehaviour {

	private bool rayHit;
	private string objectName;

	public InteractObject (bool rayHit, string objectName)
	{
		this.rayHit = rayHit;
		this.objectName = objectName;
		Debug.Log (objectName);
	}

Thanks in advance.

Passing arguments into a constructor via AddComponent is not supported out of the box in Unity but it is actually possible to pull it off:

  1. Create an AddComponent extension method for GameObject that accepts arguments. This method will first store the arguments in a static container, then add the component to the GameObject, and finally clear the arguments from the container.

  2. In the default (parameterless) constructor of your component fetch the provided arguments from the container and pass them to another constructor in the same class which accepts the arguments.

    public static class GameObjectExtensions
    {
    public static TComponent AddComponent<TComponent, TFirstArgument, TSecondArgument>
    (this GameObject gameObject, TFirstArgument firstArgument, TSecondArgument secondArgument)
    where T : MonoBehaviour
    {
    Arguments<TFirstArgument, TSecondArgument>.First = firstArgument;
    Arguments<TFirstArgument, TSecondArgument>.Second = secondArgument;

        var component = gameObject.AddComponent<TComponent>();
    
        Arguments<TFirstArgument, TSecondArgument>.First = default;
        Arguments<TFirstArgument, TSecondArgument>.Second = default;
    
        return component;
    }
    

    }

    public static class Arguments<TFirstArgument, TSecondArgument>
    {
    public static TFirstArgument First { get; internal set; }
    public static TSecondArgument Second { get; internal set; }
    }

    public class InteractObject : MonoBehaviour
    {
    private bool rayHit;
    private string objectName;

    public InteractObject(bool rayHit, string objectName)
    {
        this.rayHit = rayHit;
        this.objectName = objectName;
        Debug.Log(objectName);
    }
    
    public InteractObject() : this(Arguments<bool, string>.first, Arguments<bool, string>.second) { }
    

    }

Usage:

InteractObject instancedClass = gameObject.AddComponent<InteractObject, bool, string>
                                                       (true, hit.collider.gameObject.name);

One of the coolest things about this pattern is that you can actually assign arguments into read-only fields and properties in the constructor :o

I have an asset called Init(args) that implements a pattern similar to this (but with bells and whistles).

I know this is an old question but don’t believe Wuzseen’s answer addresses the OP’s issue directly. If I’m not mistaken OP is looking to instantiate their class the way any programmer would expect their class to but Unity’s methods for adding GameObject components does not incorporate class constructors. Something I’ve done that works, which unfortunately makes no use of the class constructor, is instead of making a class constructor use a void method the same way you would your constructor and call it directly after adding to your GameObject. For example:

test = this.gameObject.AddComponent(typeof(InteractObject)) as InteractObject;
test.InteractObjectConstructor(true, "String");

where your class would then contain:

public class InteractObject : MonoBehaviour
{
    private bool rayHit;
    private string objectName;

    public void InteractObjectConstructor (bool rayHit, string objectName)
    {
        this.rayHit = rayHit;
        this.objectName = objectName;
        Debug.Log (objectName);
    }
...
}

the down side to this method is your class constructor is not called automatically.

If you want constructor like behavior that returns an instance of a Component (that derives MonoBehavior) on a NEW game object here’s what you’ll need to do:

public class Foo : MonoBehavior {    
   public static Foo MakeFooObject() {
      GameObject go = new GameObject("FooInstance");
      Foo ret = go.AddComponent<Foo>();
      // do constructory type stuff here, you can add parameters if you want but you're manipulating the instance of Foo from the line above.
   return ret;
   } 
}

So the key piece of ingenuity here is making a static method that creates a new gameobject and adds this component to it.

I didn’t check the code for compilation so small disclaimer copying that might work.

However this isn’t really your question.

AddComponent returns a reference of the component you added. MonoBehaviors cannot have constructors (this is a low level thing). But you can always have SetUp methods on monobehaviors that are like constructors. The static method I suggested is when you want to make a new game object and treat a monobehavior kind of like you would a normal C# object. You could extend this to accept a GameObject parameter and isntead of making a new gameobject, it adds the component to the given gameobject then calls the SetUp method of the component which is basically just a constructor.

Tried it out mainly because I wanted to change some private properties of a monobehaviour I wanted to add as a component, but I didn’t want to have any public methods accessible for that monobehaviour.

    public static void AddComponentTo(GameObject go, int _num, string _word)
    {
        VirtualMono mono = go.AddComponent<VirtualMono>();
        mono.Init(_num, _word);
        
    }

    private void Init(int _num, string _word)
    {
        num = _num;
        word = _word;
    }

So in terms of this example, I made a public static method AddComponentTo() which by default it is mandatory that the gameobject you want to add the component to is a parameter, all subsequent parameters relate to whatever you want to pass to the constructor method Init(). Overload both for whatever extra constructors you require.

Usage.

VirtualMono.AddComponentTo(go, 5, "blah!");

Where ‘go’ is some gameobject reference.

Niche situation since you could just make the Init method public and just call it after you’ve added it to a gameobject. But I’ve got my reasons to use it so other people might have some reason to use it to.

If you need the parameter accessible in Awake() or Start() you’ll have to pass in the value before AddComponent() is called. One (hacky) way to do this is passing the parameter through a static field of the monobehaviour.

    public static string ConstructorConfig;
    public string Config;
    void Awake()
    {
        if (Config == null)
        {
            Config = ConstructorConfig;
            ConstructorConfig = null;
        }
        Debug.Log("I have some " + Config);
    }

Then set the parameter just before calling AddComponent()

    InteractObject.ConstructorConfig = "parameter goodies";
    gameObject.AddComponent<InteractObject >();