Editor instantiating my MonoBehaviour child class with private constructor

Hello,

I’m new to Unity and trying to code a singleton class for controlling the game general workflow: read config file, run as dedicated server or client etc.

The doc here: Ref says I shouldn’t initialize anything in the constructor since it can be called by editor outside the intended codeflow. I wanted to test this so I put Debug.Log code in my constructor and Start method and indeed it does call the constructor without any instances of the class in the scene. Cool so this part works, but then I realized that it shouldn’t.
Since my constructor is private the editor shouldn’t be able to instantiate it but it is and it does.

What am I to make of this?

I’m not experienced with C# either so perhaps I’m missing something obvious?

MonoBehaviors are created using reflection.

This is why the documentation says don’t even bother using the constructor for anything, and instead use ‘Start’ and ‘Awake’ for setting up fields and the sort.

Why is your singleton a MonoBehavior anyway though? It should just be its own type. If you need a gameobject to hook into for things like ‘update’ and the sort, create a gameobject to use as the hook for your singleton.

I’ll give you an example.

I have a Singleton called ‘Game’, game can be accessed from anywhere. In it I have several references, including to my InventoryFactory, the current Players, and my StateManager.

The StateManager is used to hook into some events like Update, and also to set the current player control state. You know, change it from ‘menu control’ to ‘gameplay control’ to ‘paused control’, etc.

In it I create a new GameObject that persists forever (donotdestroy), attach some components to it the uncover the Update function and the sort as C# events, and use this object to attach the state scripts to.

Game Singleton:

using System;
using UnityEngine;
using Ponyo.Items;
using com.spacepuppy;
using com.spacepuppy.Utils;

namespace Ponyo
{
	public sealed class Game
    {
        #region Singleton Interface
        private static Game _inst;
        public static Game Instance
        {
            get
            {
                return _inst;
            }
        }

        /// <summary>
        /// If manager singleton has been created yet it creates the manager. It will also load inventory if loadInv is true.
        /// </summary>
        /// <param name="loadInv">load the inventory pool at creation, otherwise has to be manually loaded</param>
        public static void TryInitializeManager(bool loadInv)
        {
            if (_inst == null)
            {
                _inst = new Game(loadInv);
            }
        }

        #endregion
        #region Fields
        private Player _player;
        private StateManager _stateManager;
        private InventoryFactory _invFact;
        private GameObject _mainCam;
		#endregion
        #region CONSTRUCTOR
        private Game(bool loadInv)
        {
            _player = new Player();
            _stateManager = new StateManager();
            _invFact = new InventoryFactory();

            _stateManager.Update += this.OnUpdate;

            if(loadInv)_invFact.Load();
        }
        #endregion
        #region Properties
        public Player Player
		{
			get { return _player; }
		}
        public StateManager StateManager
        {
            get { return _stateManager; }
        }
        public InventoryFactory InventoryFactory
        {
            get { return _invFact; }
        }

        public GameObject MainCamera
        {
            get { return _mainCam; }
        }
		#endregion
		#region LevelStart/LevelEnd
		public void LevelStart(GameObject playerAvatar, GameObject mainCam)
		{
			...
		}
		public void EndLevel()
		{
			...
		}
		#endregion
		#region Methods
		public void ChangeLevel(string sname)
		{
			...
		}
		#endregion
		
		#region Event Handlers
		private void OnUpdate(object sender, System.EventArgs e)
		{
            ...
	}
}

Here is the StateManager:

using UnityEngine;
namespace com.spacepuppy
{
    public class StateManager : System.IDisposable
    {
        #region Fields
        public event System.EventHandler Update;

        private GameObject _stateObject;
        private UpdateEventHooks _updateHook;
        private AbstractState _currentState;
        #endregion
        #region CONSTRUCTOR
        public StateManager()
        {
            _stateObject = new GameObject("StateObject");
            _updateHook = _stateObject.AddComponent<UpdateEventHooks>();
            _updateHook.UpdateHook += this.OnUpdate;
            UnityEngine.Object.DontDestroyOnLoad(_stateObject);
        }
        #endregion
        #region Properties
        public AbstractState Current
        {
            get { return _currentState; }
        }
        #endregion
        #region Methods
        public void GoToNullState()
        {
            if (_currentState != null) UnityEngine.Object.Destroy(_currentState);
        }
        public AbstractState GoToState<T>() where T : AbstractState
        {
            if (_currentState != null  _currentState.GetType() == typeof(T)) return _currentState;

            AbstractState lastState = _currentState;
            if (lastState != null)
            {
                lastState.OnExitState();
                lastState.enabled = false;
            }

            _currentState = _stateObject.AddComponent<T>();
            _currentState.Init(this);
            _currentState.OnEnterState(lastState);

            if (lastState != null) UnityEngine.Object.Destroy(lastState);

            return _currentState;
        }
        public AbstractState GoToState(System.Type tp)
        {
            if (!typeof(AbstractState).IsAssignableFrom(tp)) return null;
            if (_currentState != null  _currentState.GetType() == tp) return _currentState;


            AbstractState lastState = _currentState;
            if (lastState != null)
            {
                lastState.OnExitState();
                lastState.enabled = false;
            }

            _currentState = _stateObject.AddComponent(tp) as AbstractState;
            _currentState.Init(this);
            _currentState.OnEnterState(lastState);

            if (lastState != null) UnityEngine.Object.Destroy(lastState);

            return _currentState;
        }
        public AbstractState GoToState(string sStateName)
        {
            var tp = System.Type.GetType(sStateName);
            return GoToState(tp);
        }
        #endregion
        #region Event Hook
        private void OnUpdate(object sender, System.EventArgs e)
        {
            if (this.Update != null) this.Update(this, e);
        }
        #endregion
        #region IDisposable Interface
        public void Dispose()
        {
            UnityEngine.Object.Destroy(_stateObject);
        }
        #endregion
    }

    public abstract class AbstractState : MonoBehaviour
    {
        private StateManager _manager;

        public string StateName
        {
            get { return this.GetType().Name; }
        }
        public StateManager StateManager
        {
            get { return _manager; }
        }
        public void Init(StateManager manager)
        {
            _manager = manager;
        }
        public abstract void OnEnterState(AbstractState lastState);
        public abstract void OnExitState();
    }
}

Thank you lordofduct. Very informative.
Still not clear on things though:

1.Like I said I don’t have experience with C# (or .NET). I’m more of a native C++ person and I’m not familiar with reflection concept. Had a quick look at msdn reference for C# but it didn’t clear the picture for me. I understand the idea behind it but I don’t see how this is relevant so can you please give little more detail on this thought:

  1. Does the fact that reflection is used explain why the editor is telling me: "F**k your private modifier buddy! Here’s what we’re gonna do… " ?
    Is it like it uses reflection to see what my class i all about and then instantiates it but after tweaking it into it’s own version where constructor is not private?

EDIT: Ok. I’m wild guessing here but is it that when it reflects my class the information on constructor is not carried over and so it’s pointless to put anything into the constructor sine it won’t be executed anyway and the constructor is no longer private?

The references is confusing. First I read this: Writing Scripts in C# and didn’t pay enough attention to word: " behaviour" in the sentence: “All behaviour scripts must inherit from MonoBehaviour (directly or indirectly).” Then I went herre: MonoBehaviour where it actually says all scripts derive from this class and so I concluded this is an absolute requirement. Thanks for sorting this out.

OK, I see you can actually invoke private method with Type.InvokeMember.

So this answers my second question.
Still don’t get it though. What does that even mean to invoke a member method of a type unless it’s static?
EDIT: Oh OK. It takes an instance as a parameter to do that.

EDIT2: So what about reflection being used to instantiate my MonoBehaviour child being the reason why I shouldn’t bother with constructor?

My original understanding was that it is bad to do stuff in constructor because editor may call it and execute code inside it that was intended for runtime and mess things up. Isn’t that correct? And if it is then is it OK to overcome this problem by conditioning the code inside constructor with Application.isEditor ?

Reflection will allow it to instantiate the object no matter what, even if it is private. As you’ve figured out for yourself.

The constructor should be ignored for several reasons because you can cause issues with it.

For example, if you require parameters to your constructor, it will throw errors when you try to add it as a component.

And yes, your original understanding is another valid reason to avoid the constructor when writing behaviors.

A behavior is for writing custom components that you add as a component. It is NOT required to inherit from monobehavior all the time. MonoBehaviors have to be a component of some gameobject, so if your design doesn’t need that… then don’t do that. In the end not inheriting from monobehavior when you don’t actually need a monobehavior, will mean less bloat in memory.

Thanks.

One more thing: It says in the reference not to use namespaces, that Unity doesn’t support them. I see you do use them. Can you elaborate?

EDIT: It says that about scripts and your class isn’t deriving from MonoBehaviour and so it’s not a script and so it’s OK to use namespaces. Is that correct?

Cheers

You can use namespaces if you compile your code and use the DLL in Unity instead of the source code files. I do that with Visual Studio all the time. The downside to Visual Studio is that it will not be able to attach to your Unity project as a debugger. If you need the debugging you are better of with MonoDevelop that ships with Unity.

You can use namespaces all you want. And you don’t have to compile them into a separate dll at all.

You can’t use namespaces for monobehaviors though. Your behaviors MUST be in the root namespace (no namespace), otherwise the reflection technique that is used for creating the component when you ‘AddComponent(…)’ won’t be able to find it (unity team says they’ll be changing this in the future).

This is unrelated to all code written that is NOT a behavior.

I personally find it very misleading how the documentation kind of implies that all your code will be monobehaviors. For some people this may be true, mostly for small projects from the novice group. But the more advanced projects will most likely use more than just monobehaviors. And all these special rules only pertain to the MonoBehaviors.

Best way to remember it.

Your class is only a MonoBehavior if and only if it is intended to be a component of a GameObject.

Think the composite OOP design pattern, the component design pattern is an extension of it. The component pattern here is to extend and add capabilities to generic GameObjects.

On a side note. Though the C++ standard doesn’t have Reflection built into the C++ language definition this doesn’t mean C++ doesn’t have reflection. That’s like saying C++ doesn’t have strings… sure it does, you just need to have the library with it implemented.

C# language specification technically doesn’t have Reflection either. It’s not built into the language. It’s that the runtime we run C# in has a standard library implemented for us. Instead of in C++ where you choose which libraries we use, our target runtime decides for us. The two major runtimes are .Net and Mono, and both have the standard ‘System’ library which contains Reflection tools.

This is true as long as we speak about the non DLL solution. If you’re compiling your code your MonoBehaviours are allowed to have a namespace.

Your previous statement wasn’t clear about that.

You said you could use namespaces if you compile them into a dll, not that you could use them for monobehaviors if you compiled them into a dll.

The previous implies exclusivity.

This is actually similar to my issue with the unity3d documentation of monobehaviors. Their wordings imply that you must use monobehaviors. And I’m obviously not alone in inferring such things, as OP did as well.

Also, I haven’t seen this before. Can you really use namespaces with MonoBehaviors and attach them as components as long as you compile them into a dll?

I know you can have a monobehavior in a namespace, but not use it as a component. I do this to create abstract component types that don’t ever get added to a GameObject, and then create explicit behaviors in the root namespace inherit from said abstract behavior.

How do you go about adding a component from a different namespace, compiled into a dll, to a GameObject in a scene?

The component from a different namespace located in a DLL will show up in the Component->Scripts menu.You can further improve that by adding an AddComponentMenu attribute to your MonoBehaviour and then it will show up in the location you specify.

I actually made some notes regarding source files VS DLLs. This is probably not a complete list and is targeted towards C#. I used this list for my own evaluation to figure out how I wanted to work with my code.

Source files

Flash support
I don’t know if this has changed since I wrote the notes

DLLs

Missing file name and line number for errors (Visual Studio issue)
By default Visual Studio creates PDB files which contains the file names and line numbers that is used in the error messages. Unity uses Mono and Mono does not support PDB files. So unless you’re converting the PDB file to an MDB file you’re not going to get file names and line numbers when an error occurs. Unity includes a binary that can do that conversion, the name of the binary is “pdb2mdb”.

Namespaces for MonoBehaviour classes
All kinds of types can be located within a namespace.

Obfuscation
Being in control of the compilation also means that you can obfuscate your code so it won’t be that easy to decompile.

Custom preprocessor defines
Easier to work with than using RSP files.

Own framework
You can pack your own framework into two files (DLL and MDB).

Interesting, I’ll have to test this.

I wonder why they’d make external dll’s support namespaces, but not local source files, for monobehaviors.

It drives me mad that I can’t organize my stuff into namespaces.

You’re right, that’s actually quite a brain teaser

Namespace support was actually my primary reason for going with DLLs.