C# Abstract methods with default parameters
I wrote an abstract class CompositeConnector declaring abstract methods. One of them, DrawContent has a default string parameter.
public abstract class CompositeConnector : ScriptableObject
{
// ...
public abstract void DrawContent(GUISkin skin, float zoom_factor, string control_name = "");
// ...
}
Other classes inheriting from CompositeConnector also declare a default parameter.
public class InputTextConnector : CompositeConnector
{
// ...
public override void DrawContent(GUISkin skin, float zoom_factor, string control_name = "")
{
// ...
}
// ...
}
My problem comes when I call this method without the latest parameter.
// Produces the error.
_input_connector.DrawContent(_skin, _zoom_factor);
// No error.
_input_connector.DrawContent(_skin, _zoom_factor, "");
I get an error such as (not at runtime):
Unhandled Exception: System.ArgumentException: Key duplication when adding: Void DrawContent(UnityEngine.GUISkin, Single, System.String)
As you can see if I set the parameter and don't rely with the default value I don't get the error. I tried a lot of various combination but the only solution I found was to not use default parameters.
Is this a known issue? Am I trying to do something wrong here? As it seems to be valid in C# is this coming from Unity?
Answer by Bunny83 · Dec 05, 2015 at 02:09 PM
Well, i don't get that error in Unity 5.2.1f1. Are you sure:
you have the InputTextConnector class in a seperate file called "InputTextConnector.cs"?
you create an instance with the CreateInstance method of ScriptableObject?
Apart from that i don't see any reason why specifying two default parameters. Default parameters are just syntactic sugar and are actually implemented different depending on the compiler.
For example if you declare your methods like this;
public abstract void DrawContent(GUISkin skin, float zoom_factor, string control_name = "base");
// ...
public override void DrawContent(GUISkin skin, float zoom_factor, string control_name = "derived")
{
Debug.Log("DrawContent: " + zoom_factor + ", " + control_name);
}
You probably can't guess what the result is in the following cases:
// in Unity
InputTextConnector i = ScriptableObject.CreateInstance<InputTextConnector>();
CompositeConnector c = i;
i.DrawContent(null, 0f);
c.DrawContent(null, 0f);
In Unity you will get two times
"DrawContent: 0, base"
"DrawContent: 0, base"
Doing the same thing in normal C# (of course removing the ScriptableObject inheritance)
InputTextConnector i = new InputTextConnector();
CompositeConnector c = i;
i.DrawContent(null, 0f);
c.DrawContent(null, 0f);
In a C# console applciation we get this:
"DrawContent: 0, derived"
"DrawContent: 0, base"
Default parameters are just syntactic sugar. The compiler literally adds the default parameter to the call. Now it depends on how the compiler determines the default parameter. C# clearly uses the variable type while Unity's Mono compiler uses the "first declared" default value.
So it's quite dangerous to rely on different default values for different derived classes. You should only specify one default value for the same parameter.
Thanks for your answer!
To answer the first part of your answer: yes, I have a separate file for InputTextConnector and I use CreateInstance. So... I don't know where the problem's from :/ Also not that I'm on Unity 5.2.3f1 (but I don't think the problem comes from here).
About the second part, it was not clear in the code but I don't need different default parameters. Using "" as default would be fine. However when I don't specify a default parameter in the override method I get some errors.
Anyway, thanks again for your long and clear answer.