Skip to main content
Version: v3

CenterBase

Important Attention Reminder

Coding Style wiki


CenterBase<TCenter, TClass> is the abstract registration center base class of CenterFrame. It has a built-in thread-safe singleton and a type-safe Dictionary<int, TClass> cache, providing a unified object management interface — register (Add), remove (Delete), and look up (Find). APICenter (APIBase) and EventCenter (EventBase) both build on it as their shared base, and you can also implement your own center with a custom TClass base type.

NamespaceOxGFrame.CenterFrame
Typepublic abstract class
SourceCenterBase.cs
using OxGFrame.CenterFrame;

Declaration

public abstract class CenterBase<TCenter, TClass> where TCenter : CenterBase<TCenter, TClass>, new()

Generic Parameters

Generic ParameterDescription
TCenterThe center subclass itself (CRTP self-referencing constraint); it must have a parameterless constructor (new()).
TClassThe base type of the managed objects (such as APIBase for APICenter or EventBase for EventCenter).

When inheriting, pass the subclass itself and the managed base type as the generic parameters:

public class APICenterExample : CenterBase<APICenterExample, APIBase> { /* ... */ }
public class EventCenterExample : CenterBase<EventCenterExample, EventBase> { /* ... */ }

How It Works

Singleton & Registration Timing

CenterBase<TCenter, TClass> has a built-in thread-safe lazy singleton (double-checked locking). The first call to any Default API static method automatically creates the TCenter instance and runs its constructor; it is recommended to register your objects with Register in the subclass constructor.

Important Never call any Default API static method (such as Add / Find) inside the subclass constructor — it recurses through GetInstance() and causes a StackOverflow (infinite loop). Use the instance methods (such as Register) in the constructor instead.

ID Rules

  • Each registered object is cached under a unique int id. The generic overloads without an id use typeof(UClass).GetHashCode() as the id (so only one instance per type can be registered this way).
  • The overloads with an id let you assign custom ids, allowing multiple instances of the same type.
  • Registering a duplicate id logs a warning and is skipped — the existing object is not overwritten.

Default API vs Instance Methods

The static Default APIs (Add / Delete / Find) are forwarded through the singleton to the corresponding instance methods (Register / Remove / Get):

  • Callers: use the Default APIs directly on the subclass name (e.g. EventCenterExample.Find<UClass>()).
  • Inside the subclass (constructor): use the instance methods (e.g. this.Register<UClass>()).

Attention CenterBase is only responsible for object registration and cache management. If a managed object holds Unity assets (such as prefabs), make sure to release them properly (in conjunction with AssetLoaders) before removal.

Inheritance Example

An EventCenter-style example with a custom event center and event class:

using Cysharp.Threading.Tasks;
using OxGFrame.CenterFrame;
using OxGFrame.CenterFrame.EventCenter;
using UnityEngine;

// Custom event center: TCenter is the subclass itself (CRTP), TClass is the managed base type
public class EventCenterExample : CenterBase<EventCenterExample, EventBase>
{
public EventCenterExample()
{
// Register events in the constructor (instance method Register only — never Default APIs here)
this.Register<EventMsgTest>();
}
}

// Custom event: inherit EventBase
public class EventMsgTest : EventBase
{
private string _message;

public void Emit(string message)
{
this._message = message;
this.HandleEvent().Forget();
}

public async override UniTaskVoid HandleEvent()
{
// Handle the event content
Debug.Log($"Received message: {this._message}");
this.Release();
}

protected override void Release()
{
// Release the data held by the event
this._message = null;
}
}

Callers look up the event through the Default API and dispatch it:

// Find the registered event by type and dispatch it
EventCenterExample.Find<EventMsgTest>()?.Emit("Hello OxGFrame");

An APICenter-style center works the same way — just use APIBase as TClass:

using OxGFrame.CenterFrame;
using OxGFrame.CenterFrame.APICenter;

// APIGetPlayerData is a custom API class inheriting APIBase
public class APICenterExample : CenterBase<APICenterExample, APIBase>
{
public APICenterExample()
{
this.Register<APIGetPlayerData>();
}
}

Reminder You can quickly create subclasses from the templates via the Project window context menu: Create → OxGFrame → Center Frame → Event Center / API Center → Template Scripts.

Member Overview

Static Methods (Default API)

Called directly on the subclass name after inheriting (e.g. EventCenterExample.Find<UClass>()).

MethodDescription
AddInstantiates and registers an object in the cache.
DeleteRemoves an object from the cache.
DeleteAllClears all objects in the cache.
Find<UClass>Looks up an object in the cache and returns it cast to the target type.

Instance Methods

MethodDescription
Get<UClass>Gets an object from the cache and casts it (instance version of Find).
Has<UClass>Checks whether an object is registered.
RegisterRegisters an object in the cache (instance version of Add).
RemoveRemoves an object from the cache (instance version of Delete).
RemoveAllClears the cache (instance version of DeleteAll).

Protected Members (available to subclasses)

MemberTypeDescription
GetInstance()static TCenterGets the center singleton (lazily created, thread-safe).
GetFromCache(int id)TClassFetches an object from the cache; if not found, logs an error and returns default.
HasInCache(int id)boolChecks whether the given id exists in the cache.

Add

public static void Add<UClass>() where UClass : TClass, new()
public static void Add<UClass>(int id) where UClass : TClass, new()
public static void Add(int id, TClass @class)

Parameters

ParameterTypeDescription
idintRegistration id. When omitted, typeof(UClass).GetHashCode() is used as the id.
@classTClassAn existing object instance (registered under the given id).

Description

Instantiates (new UClass()) and registers an object in the cache, or registers an existing instance under the given id.

Attention
  • The generic overloads require UClass to have a parameterless constructor (new() constraint).
  • Registering a duplicate id logs a warning and is skipped; the existing object is not overwritten.

Example

// Register with the type hash as the id
EventCenterExample.Add<EventMsgTest>();

// Register an existing instance under a custom id
EventCenterExample.Add(0x01, new EventMsgTest());

Delete

public static void Delete<UClass>() where UClass : TClass
public static void Delete(int id)

Parameters

ParameterTypeDescription
idintRegistration id. When omitted, typeof(UClass).GetHashCode() is used for the lookup.

Description

Removes a registered object from the cache; does nothing if not found.


DeleteAll

public static void DeleteAll()

Description

Clears all registered objects in the cache.


Find<UClass>

public static UClass Find<UClass>() where UClass : TClass
public static UClass Find<UClass>(int id) where UClass : TClass

Parameters

ParameterTypeDescription
idintRegistration id. When omitted, typeof(UClass).GetHashCode() is used for the lookup.

Returns

UClass — the matching object in the cache (cast to UClass); if not found, an error is logged and default is returned (null for reference types).

Description

Looks up a registered object in the cache and casts it automatically. The parameterless overload looks up by type hash, so it only works for objects registered without an explicit id; for objects registered with a custom id, use Find<UClass>(int id).

Example

var evt = EventCenterExample.Find<EventMsgTest>();
evt?.Emit("Hello OxGFrame");

Get<UClass>

public UClass Get<UClass>() where UClass : TClass
public UClass Get<UClass>(int eventId) where UClass : TClass

Parameters

ParameterTypeDescription
eventIdintRegistration id. When omitted, typeof(UClass).GetHashCode() is used for the lookup.

Returns

UClass — the matching object in the cache (cast to UClass); if not found, an error is logged and default is returned.

Description

Instance version of Find<UClass>, for use inside the subclass.


Has<UClass>

public bool Has<UClass>() where UClass : TClass
public bool Has<UClass>(int id) where UClass : TClass

Parameters

ParameterTypeDescription
idintRegistration id. When omitted, typeof(UClass).GetHashCode() is used for the check.

Returns

bool — whether the object is registered in the cache.

Description

Checks whether an object is registered. Useful before registering or looking up, to avoid the duplicate-registration warning or the not-found error log.


Register

public void Register<UClass>() where UClass : TClass, new()
public void Register<UClass>(int id) where UClass : TClass, new()
public void Register(int id, TClass @class)

Parameters

ParameterTypeDescription
idintRegistration id. When omitted, typeof(UClass).GetHashCode() is used as the id.
@classTClassAn existing object instance (registered under the given id).

Description

Instance version of Add. Use it to register objects in the subclass constructor (where static Default APIs must not be called). Registering a duplicate id logs a warning and is skipped.

Example

public EventCenterExample()
{
this.Register<EventMsgTest>();
}

Remove

public void Remove<UClass>() where UClass : TClass
public void Remove(int id)

Parameters

ParameterTypeDescription
idintRegistration id. When omitted, typeof(UClass).GetHashCode() is used for the lookup.

Description

Instance version of Delete; does nothing if not found.


RemoveAll

public void RemoveAll()

Description

Instance version of DeleteAll — clears all registered objects in the cache.