Add component in one line with parameters

I’m not sure I follow why components can’t have constructors.

Is it just an enforced code design practice? If not, can we add a component with a one-liner constructor?

Is it to prevent some kind of bad initialization? But isn’t AddComponent already allowed to be used only in the same places we could change the component’s values anyway? If not, couldn’t the constructor simply be limited to those cases?

In any case, I’m just wondering if we can shorten lines of code. So instead of writing something like this:

MyComponent myComponent = AddComponent<MyComponent>();
myComponent.MyInitialValue = "Initial Value";

We could write something like this:

MyComponent myComponent = AddComponent<MyComponent>("Initial Value");

Or at very least (trying to prevent horizontal scroll bars here):

MyComponent myC = AddComponent("MyComponent", "Initial Value") as MyComponent;

And, of course, allowing us to have as many parameters as we want, just like we would have on a regular constructor.

Just for reference, I’ve already shortened many lines of code by writing my own GetOrAddComponent.

AddComponent returns Component, so:

AddComponent<MyComponent>().myInitialValue = "Blah";

Using @dannyskim’s suggestion, about Factory Design Patterns…

I’m using a slightly different way of implementing. I think doing it without reflection (like AddComponent("Initial Value") ) is basically impossible. Just get my GetOrAddComponent code there and see if you can.

So, I’ve mixed up what I wanted with danny’s and this is what I came up with:

public class MyComponent : MonoBehaviour {
  string parameter = null;

  public static MyComponent CreateComponent (GameObject where, string parameter) {
    MyComponent myC = where.AddComponent<MyComponent>();
    myC.parameter = parameter;
    return myC;
  }

And then use as such:

MyComponent myC = MyComponent.CreateComponent(gameObject, "Initial Value");

The difference here is that I don’t create a GameObject, just like AddComponent does not as well. So you’re expected to pass along one (again, just like the original), to which gameObject is the current one, by code convention.

I would suggest using a Factory Design Pattern:

Not a one line solution but clean enough without coding any extra methods…

MyComponent component = AddComponent<MyComponent>();
component .value1 = "blah";
component .value2 = "bleh";
component .value3 = "blih";

or

MyComponent component = obj.AddComponent<MyComponent>();
component .value1 = "blah";
component .value2 = "bleh";
component .value3 = "blih";

It is possible to achieve this without needing to use any reflection - though it requires some ground work to be laid first:

  1. Create an interface that defines a method that can be used to pass the argument.

  2. Make the interface generic to allow defining the type of the argument in the implementing class.

  3. Create an extension method that adds the component and then passes the provided argument through the method defined in the interface.

  4. Create classes that implement the interface, assigning the received argument to a member field in the body of the method.

  5. To allow passing multiple arguments create copies of the interface and extension method with multiple generic arguments.

So first you’ll need something like this:

public interface IInitializableWithArgument<TArgument>
{
	void Initialize(TArgument argument);
}

public class MyComponent : MonoBehaviour, IInitializableWithArgument<string>
{
	public string myInitialValue;

	public void Initialize(string myInitialValue)
	{
		this.myInitialValue = myInitialValue;
	}
}

public static TComponent AddComponent<TComponent, TArgument>
    (this GameObject gameObject, TArgument argument)
        where T : MonoBehaviour, IInitializableWithArgument<TArgument>
{
	var component = gameObject.AddComponent<TComponent>();
	component.Initialize(argument);
	return component;
}

After this creating components with arguments becomes easy as pie:

MyComponent myComponent = gameObject.AddComponent<MyComponent, string>("Initial Value");

To see this pattern being put to use in practice you can take a look at my own asset Init(args).

Note that one downside with this system is that the Awake and OnEnable event functions will get called before the Initialize method, so one needs to be careful inside these functions to avoid NullReferenceExceptions taking place (there are ways around this issue as well, but it requires some more complicated code).

How about:

Learn to structure your project/code so you don’t need to add any components to gameObjects at runtime, ever.

This way components are initialized from data (serialization system), not code.

Case solved; 0 lines required, 0 cpu/brain overhead.


This is the most basic thing you can do and everyone was doing this at the beginning. But, along the way, something bad happens as programmers feel the need to prove their programming skills by dazzling themselves/others by inventing more and more complex solution to ever unchanging and the most basic program requirements.

Consider this. You can be a hip coder and re-invent a factory pattern to do this:

public class MyComponent : MonoBehaviour
{
	MyOtherComponent _myOtherComponent = null;
	Text _text = null;
	void Awake ()
	{
		_myOtherComponent = MyOtherComponent.CreateComponent( gameObject , "!ola" );
		_text = gameObject.AddComponent<Text>();
	}
	void Update ()
	{
		if( condition_is_met )
			_text.text = _myOtherComponent.parameter;
	}
}

public class MyOtherComponent : MonoBehaviour
{
	public string parameter = null;
	public static MyOtherComponent CreateComponent ( GameObject where , string parameter )
	{
		MyOtherComponent myC = where.AddComponent<MyOtherComponent>();
		myC.parameter = parameter;
		return myC;
	}
}

“cool”

OR you can be a stoic chad programmer, that understands that less code & less complexity == better for the cpu, human workhours and, in the end, the project itself:

using UnityEngine;
using UnityEngine.UI;
using NaughtyAttributes;
public class MyComponent : MonoBehaviour
{
	[SerializeField][Required] Rigidbody _rigidbody = null;
	[SerializeField][Required] Text _text = null;
	[SerializeField][Required] MyOtherComponent _myOtherComponent = null;
	void FixedUpdate ()
	{
		_rigidbody.velocity = transform.TransformDirection( Vector3.forward ) * 100;
	}
	void Update ()
	{
		if( condition_is_met )
		{
			_text.text = "hello world";
			_myOtherComponent.parameter = "!ola";
		}
	}
}

TL;DR: expect that all required fields point to valid components, partially or fully configured, end of story.