How do you instantiate a game object with a component that has fields that should only be assigned by a constructor?

It’s a difficult question to word clearly so let me explain:

I have a game object that has a Star component. Star has a couple of fields in it that are private and should only be readable, not writeable, after initialization. One of these is a StarType component, which the Star object can mutate but I want it to be private so nothing else can change it (after initialization). The other is a StarStockpile; I want this field to be set on initialization and then to be totally immutable.

First, I tried adding a method to Star called Init(StarStockpile, StarType) that sets those two fields, which resulted in the following code to create a new star:

        StarType generatedType = generator.GenerateStarType();
        GameObject newStarObject = new GameObject(generatedType.name);
        Star newStar = newStarObject.AddComponent<Star>();
        newStar.Init(stockpile, generatedType);

However, this is pretty much the same problem: Star.Init has to be public and so it can still be messed with after initialization because anything can call it.

So now I’m trying to assign a Star component to the game object after its been created through a constructor, like so:

        StarType generatedType = generator.GenerateStarType();
        Star initStar = new Star(stockpile, generatedType);
        GameObject newStarObject = new GameObject(generatedType.name);
        Star newStar = newStarObject.AddComponent<Star>();
        newStar = initStar;

But I don’t think this is working either. For one thing, my compiler is trying to tell me that I’m doing an ‘unnecessary assignment’, which means I’m not assigning the way I think I am.

In summary:

I want to be able to instantiate a GameObject with a Star component, where that Star component’s constructor is called to assign private/readonly fields on initialization (or with any other way that initializes immutable fields).

What’s going on in the second code block is that

1. you're creating a Star component using `new` (which you should never do).
  1. Then you’re creating another one using AddComponent and assigning it to a variable.

  2. Then you’re setting that variable to the first one.

So at the end of that, the second Star is the one that's on the GameObject, but you've lost the reference to it.

Short answer is, don't use `new` to make MonoBehaviours; Initialisation function is fine.

As intimated in rh_galaxy's comment, you're getting unnecessarily hung up on the `private` thing here. You've got a private field which you need some kind of public setter for. That's fine. Using an Initialisation function immediately after creation of a component is a good way to mimic a constructor, in MonoBehaviours.

Sure, you need to be careful about calling that Initialisation function at other times, but sometimes that'll be fine and just exactly what you need.

At the end of the day, you want *something* (whether it's a constructor, init function, event, whatever) that has `public` access to be able to modify the value of that private field. Whatever that something is, it creates the possibility of it being used incorrectly by someone (as your more-complex and flawed attempt to get around init functions shows). So write code that mimimises the likelihood of that, such as only setting it publicly in a function that's clearly intended for the purpose and handles any ramifications, such as your Initialisation function..