Leaving play mode does not call constructor of static class

I’m writing an editor tool for which I need to draw a simple Mesh multiple times using the Graphics.DrawMesh method. Since it’s always the exactly same Mesh being used I would like to do this:

public static class MeshUtility
{
    public static readonly Mesh MyMesh = CreateMesh();

    private static Mesh CreateMesh()
    {
        // setting up and returning a simple Mesh
    }
}

Since “const” can’t be used I’d default to using “static readonly” instead to prevent being able to overwrite the variable from outside.

This works fine after having edited any code and Unity finishing recompilation.
It also works when entering play mode.

However, it does not work after leaving play mode as the static constructor for the class (implicit or explicit) is never called. This means that “MyMesh” is never assigned so the Mesh does not get drawn.

I’d like to avoid having to use a getter which checks for null every single time like so:

public static class MeshUtility
{
    private static Mesh myMesh = null;

    public static Mesh MyMesh
    {
        get
        {
            if(myMesh == null)
            {
                myMesh = CreateMesh();
            }
            return myMesh;
        }
    }

    private static Mesh CreateMesh()
    {
        // setting up and returning a simple Mesh
    }
}

The only alternative I see would be to use an Inititialize method which needs to get called from outside though:

public static class MeshUtility
{
    private static Mesh myMesh = null;

    public static Mesh MyMesh
    {
        get
        {
            return myMesh;
        }
    }

    public static void Initialize()
    {
        myMesh = CreateMesh();
    }

    private static Mesh CreateMesh()
    {
        // setting up and returning a simple Mesh
    }
}

The codes above are abbreviated since in my actual implementation I have (currently) 4 different Meshes.
For that reason I’d like to avoid exploding the code in this way though when a one-liner per Mesh should be enough if only the static constructor worked correctly when leaving play mode.

Does anyone know a workaround for this?

Is there a particular reason why you opted for a static class and mesh reference? If you stored the mesh in an object, MonoBehaviour or ScriptableObject, making them editor-only, you wouldn’t have to deal with static constructors not being called when exiting Play Mode. In particular, since you have four different meshes, potentially sharing the same logic, you could generalize them this way instead of copypasting the same static stuff four times.

While this may seem odd or unnecessary at first, it is pretty common to do this. There are reasons one cannot even imagine that could lead to this mesh becoming null, requiring it to be regenerated when calling it. Otherwise, you get a NullReferenceException, although Unity does spoil us by minimizing the impact of thrown exceptions.

I have different other classes in which Graphics.DrawMesh is called but since they all provide their own Materials and MatieralPropertyBlocks (to pass values to my custom shader) a single unique Mesh per variant is enough.

Having it static in a static class allows me to get the reference I need to pass to DrawMesh by simply calling “MeshUtility.MyMesh” without adding even more overhead from a MonoBehaviour or ScriptableObject (creating an instance and passing it around everywhere) which would’d fit the structure of my tool anyway.

The “CreateMesh” method already is my generalization as in reality it takes 2 parameters which specify some details of how the Mesh is created. This means that the 4 Meshes can call the same method with slightly different parameters and be done with it.

No, usually they should never be able to be set to null, that’s the whole point of “readonly” so that they cannot be modified from outside (yes, I’m aware that it’s still possible to mess with the vertices/triangles but that’s another problem).
And with the Meshes being static objects in a static class they should be initialized either on startup or at the latest when they are referenced for the first time.
But it looks to me like Unity prevents this from happening when the runtime is reloaded when leaving play mode.

Every Unity developer reaches that point in development when they realize that they can either work against the engine or with the engine. Some opt to do their own thing, while others try to go with the engine, as limiting as it is at times. In your case, using static constructors clearly doesn’t work when exiting Play Mode. You could try to use EditorApplication.playModeStateChanged and when you exit the Play Mode, call or rceive some callback to some construction function instead of using actual constructors. Not sure how well that works with making the static variable readonly though.

What is the difference between having four instances of a mesh and having a static reference to a mesh? You make it sound as if it is the same in your case. If you provided more details about your tool, users here on the forum including myself could provide better support into structuring your tool.

My point is, if you already have four instances of a mesh, why would you need to access them using static references? Even if you looked into the sinlgeton pattern to provide a global instance instead of a static reference, I wouldn’t quite understand why you go the length of trying to make this accessible from everywhere, readonly so one cannot change it and so on. If users of your tool want to change it, they will find a way, if it means using Reflection to mess with it. No readonly keyword prevents people from changing stuff using Reflection. What I try to say, don’t go to deep into the rabbit hole of protecting users from themselves. Often, it is a waste of time.

It doesn’t. “readonly” can only be set from within a real constructor (or as field initializer which gets called by the implicit constructor) so I’d still have to use a getter.

A singleton IS static itself. It’s handy in a few cases where you want to pass a reference (e.g. of an object which implements an interface, which you can’t do with just statics) but not needed for my case since it just adds extra overhead.

I never said this was meant for other users to manipulate. Look up “encapsulation”. Despite every other tutorial video on youtube teaching you to make every single class a MonoBehaviour and all variables public, this is generally not a good idea.

Oh, I know very well what encapsulation is and how Unity doesn’t do it, not even in most of their tutorials and script references. I agree with you here, ecapsulation is important and most of the times, it gets very frustrating once you realize that Unity doesn’t like you doing it, in your case the issue with static constructors.

That being said, you are in for hard times if you keep working against the engine. Everyone coming from actual IT background working with Unity comes to that point and you can keep pushing against the limitations of the engine or accept that there is little you can do and look for a solution within the engine. Unity doesn’t call static constructors after exiting Play Mode and you cannot receive a callback and use an initialization method because readonly can only be set in a real constructor. There is no going on from there. You are stuck. So why make this variable static? Why make it readonly? There are many many design patterns that require neither of these keywords and work well with Unity. You could write a factory that generates these meshes when needed, using a callback from play mode state changes. Then you have the meshes encapsulated inside the factory and other objects where they are needed.

In the end, this is your project and you are responsible for it. Most people eventually stop caring about encapsulating in Unity because it sometimes takes too much time and effort to get it to work while bashing your head against engine limitations. This is why people in most tutorials and videos keep going with public everything. You, you yourself are responsible for everything. What you do, has an impact and nothing else. Organizatorial encapsulation can be achieved by using namespaces, packages and custom assemblies. If someone is capable of breaking the security layer of Unity, they are probably capable of breaking your encapsulation as well.

Somehow you seem to have the idea that I’m some noobie who just discovered Unity last week. Do I need to write in the OP that I have multiple years of experience working with Unity and would like help from other people with a qualified background? Your tone of writing and nitpicking of implementation details implies the opposite.

That’s not encapsulation. You need access modifiers for encapsulation and they exist to prevent anyone (even yourself) from shooting themselves in the foot by using a member variable, method, or class they should have no access to because it’s only supposed to be used internally in some class. If they then brute-force their way in via reflection that’s their own fault.

It would work correctly if it was supposed to be called there. Apparently it is not, so it works as intended. It’s just the expected behaviour.

I don’t see any reason not to use the getter, because 1) the app domain won’t be reloaded when exiting playmode which causes 2) a disposed native mesh instance, which is enforced for everything that you generate at runtime.

I’d just go with the getter that you wanted to avoid. There’s probably no “workaround” that is more light-weight than that, as everything else involves to have more code which you try to avoid.

Yeah, i don’t think it’s something about “working against the engine”, instead it’s something about the engine working against the C# language specification. The specification: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/static-constructors said:

A static constructor is called automatically. It initializes the class before the first instance is created or any static members declared in that class (not its base classes) are referenced. A static constructor runs before an instance constructor. A type’s static constructor is called when a static method assigned to an event or a delegate is invoked and not when it is assigned. If static field variable initializers are present in the class of the static constructor, they’re executed in the textual order in which they appear in the class declaration. The initializers run immediately prior to the execution of the static constructor.

In fact, static field of other types like Matrix4x4, etc. works as intended, so the actual problem is the mesh created by calling new Mesh() is discarded after exiting play mode.

That’s good and all (and despite the 2 year necro post), but the C# side of things is just along for the ride in the context of Unity. It just a small piece of the greater whole, most of which is Unity’s black-box C++ managed side.

That said, Unity does treat C# as much as C# as it can, and static constructors are called like by the C# rules… however static values will live as long as the next domain reload. So, to answer the title of the post “Leaving Play Mode does not call constructor of static class”, is because it’s already been called at some point before, usually by entering play mode (editor settings dependant).

There’s no domain reload for exiting play mode (there’d be riots). And this behaviour is why a lot of my static class constructors look like this:

public static class MyStaticClass
{

    static MyStaticClass()
    {
        // normal runtime things

#if UNITY_EDITOR
        UnityEditor.EditorApplication.playModeStateChanged += (state) =>
        {
            if (state == UnityEditor.PlayModeStateChange.EnteredEditMode)
            {
                // tidy up
            }
        };
#endif
    }
}

I’d go as far as say is that it’s probably best practice to NOT do certain Unity API things in static constructors, as they have the potential to be invoked before Unity as a whole has woken up, taken a piss, and grabbed it’s keys as it heads out the front door. Meaning you’ll likely crash it.

It should be well known that Unity discards a lot of managed resources on exiting play mode. Not surprised that meshes are among them. In fact, it’s probably a ‘fake null’ rather than a real null, as the native object has likely been murdered without remorse on Play mode’s way out.

So at the end of the day, you still have to work within Unity’s rules. But if you know how they work… you can easily work around them to your advantage, or to meet your end goal. Wouldn’t be software design without a little challenge, would it now?

2 Likes