- Home /
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).
Why are you afraid of someone calling public Init()? It's your code that is going to run, right? Maybe you can set internal instead of public.
Answer by Bonfire-Boy · Mar 24 at 10:41 AM
What's going on in the second code block is that
new
(which you should never do).
2. Then you're creating another one using
AddComponent
and assigning it to a variable.
3. Then you're setting that variable to the first one.
new
to make MonoBehaviours; Initialisation function is fine.
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.
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..
I guess what I'm getting hung up on is that if this wasn't a component and was instead something that could be created through a constructor, in that case these fields could be made private/readonly since the constructor is allowed to initialize them and so they wouldn't need public setters at all, but because they're components I can't do that and they need public setters. I guess it just feels like a weakness of using components?
But if you really think it's fine to have a public setter and just make it super clear what its purpose is, I'll accept that.
That's fair. One way you could restrict the use of the Initialisation function is to wrap it in a static function that plays the part of a constructor. Then you can make it private. This kind of thing...
class A: MonoBehaviour
{
private void Initialise( /* params */) {}
public static A Construct( GameObject go, /*params */)
{
A result = go.AddComponent<A>();
result.Initialise(/* params */);
return result;
}
}
But for me that's a bit of a faff. Unity does make one somewhat relax ones feelings about exposing stuff. After all, you've got all those fields exposed in the editor anyway.
Your answer
![](https://koobas.hobune.stream/wayback/20220613054511im_/https://answers.unity.com/themes/thub/images/avi.jpg)
Follow this Question
Related Questions
Are my bounds right world position in this case ? 1 Answer
Checking if object intersects? 1 Answer
Instantiated prefab click script running on all instances 6 Answers
How to associate underlying data structure to prefab at runtime? 1 Answer
setting the text of an instantiated prefab's child's guitext object 1 Answer