How many parameters?

Interesting query got raised while someone was reviewing one of my pull requests today - how many parameters is too many?

For context, this is a Unity3D project for an upcoming installation. We've got a MonoBehaviour controlling some UI has serialized references to multiple text fields.

public class UIDisplay : MonoBehaviour
{
    //"Text" in here is Unity3D.UI.Text, the Unity3D text field... slightly confusingly named.
    [SerializeField]
    private Text someField;
    [SerializeField]
    private Text someOtherField;
    [SerializeField]
    private Text anotherField;
}

We're trying to treat the UIDisplay as a single widget with multiple text fields, but we need to get some strings in from a view controller further up the chain to populate those fields. A few options present themselves:

  1. Make the text fields publically accessible and have the controller set the .text property directly. That's not ideal as Text eventually inherits from Monobehaviour and there's plenty of properties on there that other upstream code might mess with.
  2. Pass the strings in as part of the constructor... unfortunately that's not possible with MonoBehaviours and in any case the behaviour is instantiated at scene start.
  3. Pass the strings in through an Init method. Not perfect, but the winner.

Having an Init method that sets those strings implies a few of things about the way the UIDisplay works, crucially that this is an initialization behaviour: It should only be done once, the text shouldn't be changed once it starts up. For this component it's absolutely right, any change in the text would result in a visual "jump" which we want to avoid (all about the smooth transitions for installation pieces.)

The initial pass at this Init method had only a single parameter, by putting all of the strings into an array:

public void Init(string[] uiText)
{
    someField.text = uiText[0];
    someOtherField.text = uiText[1];
    anotherField.text = uiText[2];
}

(side note, that wasn't actually how it was done, the real deal used alternating fields for keys/values and a switch statement - this is just a very simplified example.)

But my refactor put it towards:

public void Init(string someText, string someOtherText, string anotherText)
{
    someField.text = someText;
    someOtherField.text = someOtherText;
    anotherField.text = anotherText;
}

So calling it is crazy easy, no need to create any array:

uiDisplay.Init(
    config.GetString("something"),
    config.GetString("somethingelse"),
    config.GetString("somethingagain")
    );

But the question was, how does it scale up? 3 params is fine, but at 30? At what point is it better to bundle all the parameters up in an object (or array, or dict, or whatever)?

First of all, I figure if you find your method's param list getting a bit long you need to look at the architecture of what you're writing - is there a great reason why one method is taking in so many bits of data? Do you need to pass groups of data around further? Sure make an object.

But if it's just a component or facade that has a very involved initialization, then to hell with that. Just go for named parameters when you call the method:

uiDisplay.Init(
    someText: config.GetString("something"),
    someOtherText: config.GetString("somethingelse"),
    anotherText: config.GetString("somethingagain")
    //...heaps of other fields because it's obvious what's going on
    );

Scales up to tonnes of params neatly, but I see it so rarely in C# land. The language supports them and so should you.

Comments