- Home /
Override a serialized variable from a parent class?
What I've got now, is, in the base class:
[HideInInspector] [SerializeField] protected Button button;
...and in the derived class:
[HideInInspector] [SerializeField] RecalibrateButton _button;
_button = button as RecalibrateButton;
I'd rather do
[HideInInspector] [SerializeField] new RecalibrateButton button;
button = base.button as RecalibrateButton;
...but while that doesn't generate an error when I save the script, this error comes up shortly thereafter in the Editor:
Same name multiple times included:::Base(MonoBehaviour) button
Is there some way I can use the variable name "button" to override what the base class's "button" is?
Edit: UnityAnswers proves only abysmal ability to respond to answers, so here's what I'm doing now, in the derived class:
public override void InitializeAtRuntime () {
base.InitializeAtRuntime();
RecalibrateButton button = base.button as RecalibrateButton;
button.ReleaseInsideRange += OnReleaseInsideRange;
button.ReleaseOutsideRange += OnReleaseOutsideRange;
}
With your new code (InitializeAtRuntime()), unless you already make sure that button is assigned (i.e. not null) and of type "RecalibrateButton", you should probably have button.ReleaseInsideRange enclosed in an "if (button != null) { ... }", otherwise, you might run into trouble at some point in time.
Answer by jashan · Sep 10, 2010 at 05:04 AM
As SpikeX said - you can simply assign objects of a subclass to variables of the parent class. But obviously, there's a problem with that because you can't directly access the members that the subclass defined. So, if for example your Button has AButtonMethod() and RecalibrateButton has ARecalibrateButtonMethod(), the only way to access the latter is by doing a typecast:
((RecalibrateButton)button).ARecalibrateButtonMethod();
That's not exactly convenient, but it works. However, if RecalibrateButton overrides a method, e.g. if it has it's own definition of AButtonMethod(), the oo-runtime will automatically execute the version of RecalibrateButton when you call it. So, you might consider not creating ARecalibrateButtonMethod() when you could also override AButtonMethod(). But if that doesn't work in your specific design, you'll have to fallback to the typecast approach. One thing that I do frequently in such cases is adding a property that handles this for me (just a matter of convenience and cosmectics):
public RecalibrateButton RecalibrateButton {
get { return (RecalibrateButton) button; }
}
That way, you can conveniently access "button" as if it was a RecalibrateButton.
I only need to access "button" in the initialization stage. As I said in a response to SpikeX, I'm not happy about this, and can't believe the language doesn't provide a method for this kind of thing, but it will do. Also, is there some reason you prefer an explicit cast ins$$anonymous$$d of as? In my research, I've heard that "as" was a superior approach.
The only difference between (type) and as type is that "as" doesn't fail on a cast exception, it will ins$$anonymous$$d assign the value of "null" to the variable. Using "as" is safer if you check for null, basically, and if you don't like try/catching your exceptions. ;)
Actually, if you're not sure that the object is of the type you expect, you can easily do: if (button is RecalibrateButton) { ((RecalibrateButton)button).ARecalibrateButton$$anonymous$$ethod(); } In general, I think the prefix-casting is preferable because when you get an exception, you get an exception that tells you exactly what's going on. While when you get a NullReferenceException with "as-casting", either the object was null, or it was of the wrong type which makes debugging more difficult (even worse when the exception occurs later). The advantage of "as-casting" however, is that it's much faster.
Answer by qJake · Sep 10, 2010 at 02:31 AM
No. That's the point of deriving from classes, the derived class inherits everything from its parent classes (everything that's public and protected, anyway). What you can do, though, is something like this, inside the constructor or elsewhere:
button = new RecalibrateButton();
since the "RecalibrateButton" is of type "Button", you can instantiate it, and the "button" becomes a "RecalibrateButton", even though it was defined as a "Button". So you don't need to redefine "button" at all (in fact, don't!), instead, just create an instance of the child class inside of it.
Polymorphism - What fun :)
It is not "the point". Otherwise there would be no overriding functions. It's pitiful that you can't do this with variables, the way you can with methods and even properties. Also, the constructor-based approach won't work, as this is a specific instance of RecalibrateButton that I've got set up and serialized in the Editor.
Did you read this page? It explains polymorphism in C#: (be sure to click the "C#" header on the code samples if not already) http://msdn.microsoft.com/en-us/library/ms173152(VS.80).aspx -- I'm not 100% sure what you're trying to do, or what you're mad about, but that page might shed some light on what you can and cannot do with C#/.NET.
"Fields cannot be virtual; only methods, properties, events and indexers can be virtual." "Virtual methods and properties allow you to plan ahead for future expansion." Well, in my case, Virtual fields would do the same thing. It's a stupid limitation. There may be some important technical reason for doing things this way, but it doesn't mean that it's good for making code.
You can get an idea of what I'm doing in the edit to the question. RecalibrateButton sends two events I need to utilize (for RecalibrateButtonSounds), but Button doesn't need to send them.
Several types of button classes derive from ButtonSounds, which has a Button for its variable "button", and all of them are just fine having button be stored as a Button, despite the fact that all of them are actually derived from Button, like PauseButton, EndButton, etc, and never Button itself. That's because the classes derived from ButtonSounds use either the virtual methods from ButtonSounds, or overridden versions of them. I only need "button" serialized so the game can start faster, as I only set up event listening and then never use the variable again. In this case, I need a R...Button
Answer by Herman-Tulleken · Sep 10, 2010 at 11:26 AM
Your code is legal C#, and in my game I can get it to work if the class is not a MonoBehaviour. (Although I have not tested it with SerializeField). This makes it look like the reflection used by MonoBehviour to build inspectors, etc., might be the reason it is flagged.
The other solutions by other posters will work and are simple enough to implement, but you might also consider a refactoring which involves moving the field to a non-MonoBehaviour class. (This of course depends on the rest of your design; it might also be a terrible idea).
Everything being a $$anonymous$$onoBehaviour is necessary. The scripts are attached to specific Game Objects and deal with the attached Audio Sources.
Your answer
Follow this Question
Related Questions
Importing data from classes? 2 Answers
adding classes to arrays 2 Answers
Instantiate inside class function returns NullReference 1 Answer
Alternative way to have a class to store data 2 Answers
Is Instance Of 3 Answers