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
1
Question by necarlson · Jan 11, 2021 at 10:12 PM · prefabvirtualoverridepolymorphismderived-class

Prefab seems to break polymorphism

Instantiation seems to change which method is called (base class or derived class)
I'll admit I'm no expert in C# polymorphism, but can someone tell me what's going on here?
It seems the uninstantiated prefab will only call the base class methods, but the instantiated game object will call the derived class method.

ParentScript.cs

 using UnityEngine;
 
 public abstract class ParentScript : MonoBehaviour {
     virtual internal string firstName {get; set;} = "Mother";
     
     void Start() {
         Debug.Log("Start: " + firstName);
     }
 }


ChildScript.cs

 using UnityEngine;
 
 public class ChildScript : ParentScript {
     override internal string firstName {get; set;} = "Daughter";
 }
 

CreatorScript.cs

 using UnityEngine;
 
 public class CreatorScript : MonoBehaviour {
     // An empty gameobject with only a ChildScript component
     public GameObject prefab;
 
     void Start() {
         ParentScript parentScript = prefab.GetComponent<ParentScript>();
         Debug.Log("Before Instantiation (pulled as parent): " + parentScript.firstName);
 
         ChildScript childScript = prefab.GetComponent<ChildScript>();
         Debug.Log("Before Instantiation (pulled as child): " + childScript.firstName);
 
         ChildScript asChildScript = (parentScript as ChildScript);
         Debug.Log("Before Instantiation (as child): " + asChildScript.firstName);
 
         ChildScript castChildScript = (ChildScript) parentScript;
         Debug.Log("Before Instantiation (cast as child): " + castChildScript.firstName);
 
         GameObject p = Instantiate(prefab, Vector3.zero, Quaternion.identity);
         Debug.Log("After Instantiation (prefab): " + parentScript.firstName);
 
 
         ParentScript instantiatedParentScript = p.GetComponent<ParentScript>();
         Debug.Log("After Instantiation (instantiated - pulled as parent): " + instantiatedParentScript.firstName);
         ChildScript instantiatedChildScript = p.GetComponent<ChildScript>();
         Debug.Log("After Instantiation (instantiated - pulled as child): " + instantiatedChildScript.firstName);
     }
 }
 

Console Output

 Before Instantiation (pulled as parent): Mother
 UnityEngine.Debug:Log (object)
 CreatorScript:Start () (at Assets/CreatorScript.cs:9)
 
 Before Instantiation (pulled as child): Mother
 UnityEngine.Debug:Log (object)
 CreatorScript:Start () (at Assets/CreatorScript.cs:12)
 
 Before Instantiation (as child): Mother
 UnityEngine.Debug:Log (object)
 CreatorScript:Start () (at Assets/CreatorScript.cs:15)
 
 Before Instantiation (cast as child): Mother
 UnityEngine.Debug:Log (object)
 CreatorScript:Start () (at Assets/CreatorScript.cs:18)
 
 After Instantiation (prefab): Mother
 UnityEngine.Debug:Log (object)
 CreatorScript:Start () (at Assets/CreatorScript.cs:21)
 
 After Instantiation (instantiated - pulled as parent): Daughter
 UnityEngine.Debug:Log (object)
 CreatorScript:Start () (at Assets/CreatorScript.cs:25)
 
 After Instantiation (instantiated - pulled as child): Daughter
 UnityEngine.Debug:Log (object)
 CreatorScript:Start () (at Assets/CreatorScript.cs:27)
 
 Start: Daughter
 UnityEngine.Debug:Log (object)
 ParentScript:Start () (at Assets/ParentScript.cs:7)
 

Note: The scene is just a single empty game object with a CreatorScript component
Note: GetType() for any of these will return ChildScript

For what it is worth, this is the simplest example I could create, but in my real project, I have an uninstantiated prefab where I know it's script's base class, but not the derived class. So I can get the script with var script = GetComponent<BaseClass>() but when I go to call any method, it is useless as it only calls the base class method. Even explicitly casting to the child class doesn't seem to help.

(and c# won't allow the kind of dynamic typing that would normally get one out of this situation)

(If anyone cares, in the real project, the base class has many properties of different types, and each derived class will only override a handful, so dictionaries or abstract methods or other solutions I would normally go with wont help)

Comment
Add comment
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

1 Reply

· Add your reply
  • Sort: 
avatar image
0

Answer by logicandchaos · Jan 11, 2021 at 10:31 PM

That is normal behaviour for C#, if you want to be able to call child methods from a base class reference you need to make a virtual method in the base class and then override it in the child class.

Comment
Add comment · Show 1 · 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 necarlson · Jan 12, 2021 at 01:46 PM 0
Share

That is what I did, is it not?
The property is virtual in the parent class and overriden by the child class. Furthermore, the logging shows that the prefab is returning the parent method for:
1. prefab.GetComponent<ParentScript>()
2. prefab.GetComponent<ChildScript>()
3. ParentScript used as ChildScript
4. ParentScript explicitly cast as ChildScript

The only time the child method seemed to be called was on the instantiated gameobject the prefab created, but not the prefab itself.
(Note that the prefab has the ChildScript as its only component)

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

153 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

Related Questions

How do I call a method in derived class? 1 Answer

Using Undo.RecordObject() does not protect a component's variables from being reverted to the prefab on play. 0 Answers

unity doesn't recognize the derived class 3 Answers

How to call child overide function? 1 Answer

Assigning child script to parent field in Inspector 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