Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
2 captures
13 Jun 22 - 14 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by bigpawh · Mar 22 at 05:00 PM · instantiateencapsulation

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).

Comment
Add comment · Show 1
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image rh_galaxy · Mar 22 at 07:48 PM 0
Share

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.

1 Reply

· Add your reply
  • Sort: 
avatar image
2
Best Answer

Answer by Bonfire-Boy · Mar 24 at 10:41 AM

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).
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.


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..
Comment
Add comment · Show 2 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image bigpawh · Mar 24 at 05:09 PM 0
Share

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.

avatar image Bonfire-Boy · Mar 24 at 05:28 PM 0
Share

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

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

159 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

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


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges