Dependency management for lazy loaded components

I’ve figured out that it would be a good idea to lazy load and later destroy some of the MonoBehaviours that won’t be used often, like AuthManager (log in, log out), GooglePlayManager (link account with GPG, sign in with GPG after a logout), etc., but now I’m facing a problem with dependencies since I’ve been using [SerializeField] to provide them through the Inspector, and dynamically added components/GOs (lazy loading) couldn’t use that approach. How can I provide dependencies for lazy-loaded components? I don’t like Singletons because of maintainability and tastability issues. For DI frameworks people on the internet generally say that they should only be used for complex scenarios and that they are an overkill for most of the things. Are there any other options? Is DI my only option here?

Why are these things MonoBehaviours/managers in the first place? A login sounds like a static async method, not something that has to be Instantiated, attached to a GameObject and later on Destroyed.

If you’re thinking of something like an entire login menu that needs to have a bunch of visuals and whatnot, then you do have to instantiate a GameObject hierarchy. In those cases, I’d still have a static async method that deals with it, and then loads the menu from Addressables, Instantiates it, and Destroys it. Don’t do anything like DI before you actually have two different versions of the dependency to inject. You’re not going to have more than one login screen.

1 Like

I’m not really sure what your question is, but if you’re trying to make sure dynamically-fabricated MonoBehaviours have everything they need when created, I use this pattern a lot.

It provides a nice “gate” where all parts necessary must be present before doing a step, and it can cascade nicely from one to the next, and it also provides good documentation built right into the code (“to make an X you will need to give it an A and a B”), and helps you recall how to use your stuff even years later when you dig it up.

Factory Pattern in lieu of AddComponent (for timing and dependency correctness):

1 Like

They’re MonoBehaviours just because I’m using serialized fields to provide dependencies using the Inspector, and because I saw in the Unity UGS Authentication docs that they’re using them. I realize now that they can be standard C# classes.

I actually have pages for log-in, registration, but the UI interactions are handled in separate MB classes just for that purpose, and the actual logic for authentication is in before mentioned classes, AuthManager, GooglePlayManager.

If I’m going to use standard C# classes, how should I provide dependencies (without using DI frameworks). Have a class with static variables for all dependencies? Is that the only solution? I already have a SO called “GlobalRefs” with non-static fields for all dependencies that are needed across scenes, since you cannot drag GOs from other scenes into serialized fields.

You could use scriptable object assets to create Inspector-assignable soft references to your services, and then then do bookkeeping on how many clients are using each service at any given time, and dispose them when they’re no longer needed.

public TService Get()
{
	clients++;
	return service ??= CreateService();
}

public Release()
{
	clients--;

	if(clients== 0)
	{
		DisposeService();
	}
}

So similar to what AssetReference.LoadAssetAsync / ReleaseAsset do - but with a little scriptable object twist.

1 Like