Class UnityServiceLocator
A service locator that provides runtime access to globally shared IUnityGameService instances without requiring direct references between systems.
public class UnityServiceLocator
Inheritance
Examples
// Bootstrap — call once at application startup (e.g. from Bootstrapper.Awake):
UnityServiceLocator.Initialize();
UnityServiceLocator.Current.Register(new UnityEventAggregator());
// Later, anywhere that needs the event aggregator:
if (UnityServiceLocator.Current.TryGet(out var aggregator))
{
aggregator.Publish(new PlayerMovedMessage(transform.position));
}
// Service components self-register in Awake and unregister in OnDestroy:
private void Awake() => UnityServiceLocator.Current.TryRegister(this);
private void OnDestroy() => UnityServiceLocator.Current.TryUnregister(this);
Remarks
The locator is initialised by the bootstrapper before any scene Start call runs, so
services are always available when game objects need them. The single Current
instance is intentionally created via Initialize rather than a static
field initialiser so that tests can call Initialize to reset state between runs.
Properties
Current
Gets the active global service locator instance.
public static UnityServiceLocator Current { get; }
Property Value
Methods
ForceRegister<T>(T)
Registers the service of type T, overwriting any existing registration
for that type without logging an error.
public void ForceRegister<T>(T service) where T : IUnityGameService
Parameters
| Name | Type | Description |
|---|---|---|
service | T | The service instance. |
Type Parameters
| Name | Type | Description |
|---|---|---|
T | The type of the service. |
Remarks
Use in testing (to inject a mock) or during hot-reload scenarios where intentional replacement is expected. In production bootstrapper code prefer Register` so accidental double-registration is caught early.
ForceUnregister<T>()
Removes the registration for type T unconditionally, regardless of
which instance is currently registered.
public void ForceUnregister<T>() where T : IUnityGameService
Type Parameters
| Name | Type | Description |
|---|---|---|
T | The type of the service. |
Remarks
The escape hatch for teardown scenarios where the registered instance may have already been replaced or is unknown — for example, when a test fixture tears down the service locator state without knowing which concrete implementation was registered.
Get<T>()
Returns the registered service of type T, throwing if it is not found.
public T Get<T>() where T : IUnityGameService
Returns
T — The registered service instance.
Type Parameters
| Name | Type | Description |
|---|---|---|
T | The type of service to retrieve. |
Remarks
Use this overload when the service is guaranteed to be present by the time the caller runs
(i.e., registered before any scene Start). An exception here signals a programming
error in the bootstrapper — the service should have been registered and wasn't. Prefer
TryGet` in any code path where the service is optional or the registration
order is uncertain.
Exceptions
InvalidOperationException — Thrown when T is not registered.
Initialize()
Creates the global service locator instance if one does not already exist.
public static void Initialize()
Remarks
The null-coalescing assignment (??=) makes this call idempotent — calling it more
than once (e.g. across domain reloads in the editor) leaves the existing instance and its
registered services untouched rather than wiping them.
Register<T>(T)
Registers the service of type T, asserting that no prior
registration exists for that type.
public void Register<T>(T service) where T : IUnityGameService
Parameters
| Name | Type | Description |
|---|---|---|
service | T | The service instance. |
Type Parameters
| Name | Type | Description |
|---|---|---|
T | The type of the service. |
Remarks
Use this during bootstrapper setup where double-registration would be a programming
error. If the type is already registered, an error is logged and then
Dictionary.Add throws ArgumentException — the intent is to
surface the mistake loudly rather than silently overwrite an existing service.
For intentional replacement, use ForceRegister` instead.
Exceptions
ArgumentException — Thrown by Dictionary.Add when T is already registered.
TryGet<T>(out T)
Attempts to retrieve the service of type T without throwing.
public bool TryGet<T>(out T GameService) where T : IUnityGameService
Parameters
| Name | Type | Description |
|---|---|---|
GameService | T | The retrieved service, or default if not found. |
Returns
bool — true if the service was found; otherwise, false.
Type Parameters
| Name | Type | Description |
|---|---|---|
T | The type of service to retrieve. |
Remarks
The safe counterpart to Get`. Use when the service might legitimately be absent — for example, when a feature is optional or when calling from a component that can run before the bootstrapper has finished registering all services. A warning is logged on miss so that missing registrations remain visible in the console.
TryRegister<T>(T)
Registers the service of type T only if nothing is already registered
for that type.
public bool TryRegister<T>(T service) where T : IUnityGameService
Parameters
| Name | Type | Description |
|---|---|---|
service | T | The service instance to register. |
Returns
bool — true if the service was registered; false if one was already present.
Type Parameters
| Name | Type | Description |
|---|---|---|
T | The type of the service. |
Remarks
Designed for MonoBehaviour services that self-register in Awake. In Unity, Awake
can fire multiple times across scene loads (domain-reload-off mode, additive scenes), so using
[Register](UnityServiceLocator.mdx) in Awakewould log spurious errors on subsequent loads.TryRegister` is safe to call repeatedly — it silently no-ops when a registration already
exists.
TryUnregister<T>(T)
Removes the registration for type T only if the registered instance
matches service.
public bool TryUnregister<T>(T service) where T : IUnityGameService
Parameters
| Name | Type | Description |
|---|---|---|
service | T | The specific service instance to remove. |
Returns
bool — true if the service was removed; false if not registered or if the
registered instance does not match.
Type Parameters
| Name | Type | Description |
|---|---|---|
T | The type of the service. |
Remarks
The instance comparison prevents one system from accidentally unregistering a service that was replaced by another system — for example, if a new scene registered a fresh instance under the same type, an old teardown callback will fail rather than silently removing the replacement. Use ForceUnregister` when you need to remove regardless of which instance is currently registered.
Unregister<T>(T)
Removes the registration for type T, logging an error if the
service is not found or if the registered instance does not match service.
public void Unregister<T>(T service) where T : IUnityGameService
Parameters
| Name | Type | Description |
|---|---|---|
service | T | The specific service instance to remove. |
Type Parameters
| Name | Type | Description |
|---|---|---|
T | The type of the service. |
Remarks
Mirrors TryUnregister` but treats a failed removal as an error rather than a recoverable condition. Use in places where the service is guaranteed to have been registered by this caller and its absence would indicate a lifecycle bug.