Class SerializationEngine
Internal serialization engine that manages the global type-serializer registry, dispatches read and write operations to the correct ITypeSerializer, and creates serializers on demand for types that do not have one pre-registered.
Inherited Members
Namespace: Scylla.Core.Util.Serialization
Assembly: ScyllaCore.dll
Syntax
public static class SerializationEngine
Remarks
SerializationEngine is a low-level internal class. Application code should
interact with the serialization system exclusively through the
ScyllaSerialization facade. Direct access to this class is only
necessary when implementing custom infrastructure (e.g. a new
IScyllaWriter or a new IScyllaReader).
Initialization: the engine uses a double-checked lock pattern inside EnsureInitialized() to guarantee that Scylla.Core.Util.Serialization.SerializationEngine.RegisterDefaultSerializers() runs exactly once across all threads. The ScyllaSerialization static constructor calls EnsureInitialized() before any serialization method can be reached.
Serializer resolution order for a given Type:
- Direct cache lookup in
_serializers. Nullable<T>unwrapping - delegates to the underlying type's serializer.- Enum detection - creates a new EnumSerializer<T> via reflection.
- Array detection - creates an
ArraySerializer<T>for the element type. - Generic collection detection -
List<T>,Dictionary<K,V>,HashSet<T>,Queue<T>,Stack<T>. - Fallback - creates a ReflectionSerializer for any other type.
Dynamically created serializers are cached immediately after creation to avoid repeated reflection overhead.
Cache eviction: when the cache grows beyond
Scylla.Core.Util.Serialization.SerializationEngine.MAX_SERIALIZER_CACHE_SIZE entries, Scylla.Core.Util.Serialization.SerializationEngine.TrimCache() is
called to remove up to Scylla.Core.Util.Serialization.SerializationEngine.CACHE_CLEANUP_COUNT dynamically-generated
serializers while preserving the fixed set of built-in serializers. A
Debug.LogWarning is emitted when trimming occurs so that applications
with many dynamic types can detect the condition and call
ClearCache() proactively at suitable points (e.g. scene transitions).
Methods
ClearCache()
Clears all cached serializers and resets the engine to its uninitialized state. The next call to any operation will re-run Scylla.Core.Util.Serialization.SerializationEngine.RegisterDefaultSerializers().
Declaration
public static void ClearCache()
Remarks
Intended for use during scene transitions or in editor tooling where long-running processes might accumulate many dynamically-generated serializers for types that are no longer in use. After clearing, all custom serializers registered via RegisterSerializer<T>(ITypeSerializer<T>) must be re-registered if they are still needed.
This method acquires _registrationLock to ensure thread safety with
concurrent EnsureInitialized() calls.
EnsureInitialized()
Ensures that the engine is initialized with all built-in default serializers. Subsequent calls after the first are no-ops.
Declaration
public static void EnsureInitialized()
Remarks
Uses a double-checked locking pattern for thread safety: the
_initialized flag is checked once without the lock for the common fast
path, then checked again inside the lock to prevent duplicate initialization if
multiple threads enter concurrently. The ScyllaSerialization
static constructor calls this method automatically; it does not need to be called
by application code.
GetSerializer(Type)
Looks up or creates the ITypeSerializer for the specified
type, following the full resolution chain documented on the
class-level remarks.
Declaration
public static ITypeSerializer GetSerializer(Type type)
Parameters
| Type | Name | Description |
|---|---|---|
| Type | type | The Type for which a serializer is needed. Must not be |
Returns
| Type | Description |
|---|---|
| ITypeSerializer | The resolved ITypeSerializer for |
Remarks
Nullable<T> types are transparently unwrapped: the serializer for
the underlying value type is returned, and nullability is handled by the caller
via PeekToken() before calling
ReadValue(Type, IScyllaReader, ISerializationContext).
If the cache has grown beyond Scylla.Core.Util.Serialization.SerializationEngine.MAX_SERIALIZER_CACHE_SIZE, a partial eviction of Scylla.Core.Util.Serialization.SerializationEngine.CACHE_CLEANUP_COUNT dynamically-generated entries is performed before the new serializer is created.
See Also
ReadValue(Type, IScyllaReader, ISerializationContext)
Reads a value of the specified type from the given
reader, using the serializer resolved from the
context or the global registry.
Declaration
public static object ReadValue(Type type, IScyllaReader reader, ISerializationContext context)
Parameters
| Type | Name | Description |
|---|---|---|
| Type | type | The target type to deserialize. Used for serializer lookup. Must not be |
| IScyllaReader | reader | The IScyllaReader positioned at the start of the value to read.
Must not be |
| ISerializationContext | context | The current ISerializationContext providing settings and reference tracking. When non-null, its GetSerializer(Type) is consulted before the global registry, mirroring the behaviour in WriteValue(object, Type, IScyllaWriter, ISerializationContext). |
Returns
| Type | Description |
|---|---|
| object | The deserialized value as an |
Exceptions
| Type | Condition |
|---|---|
| SerializationException | Thrown if no serializer can be found for |
See Also
RegisterSerializer(Type, ITypeSerializer)
Registers a non-generic type serializer by Type key, replacing any previously cached serializer for that type.
Declaration
public static void RegisterSerializer(Type type, ITypeSerializer serializer)
Parameters
| Type | Name | Description |
|---|---|---|
| Type | type | The Type this serializer handles. Used as the lookup key.
Must not be |
| ITypeSerializer | serializer | The serializer to register. Stored directly without wrapping.
Must not be |
Remarks
This overload is used internally when registering dynamically-constructed generic
serializers (e.g. ArraySerializer<T>) where the closed generic type
is not known at compile time.
See Also
RegisterSerializer<T>(ITypeSerializer<T>)
Registers a custom type serializer globally for the type T,
replacing any previously cached serializer for that type.
Declaration
public static void RegisterSerializer<T>(ITypeSerializer<T> serializer)
Parameters
| Type | Name | Description |
|---|---|---|
| ITypeSerializer<T> | serializer | The typed serializer to register. It is wrapped in a
TypeSerializerAdapter<T> so it can be stored in the non-generic
|
Type Parameters
| Name | Description |
|---|---|
| T | The type whose serialization is handled by |
Remarks
Calls EnsureInitialized() before writing to the registry so that default serializers are always present when a custom one is added. Thread-safe because ConcurrentDictionary<TKey, TValue> assignment is atomic.
See Also
WriteValue(object, Type, IScyllaWriter, ISerializationContext)
Writes value of the specified type to the
given writer, using the serializer resolved from the
context or the global registry.
Declaration
public static void WriteValue(object value, Type type, IScyllaWriter writer, ISerializationContext context)
Parameters
| Type | Name | Description |
|---|---|---|
| object | value | The object to serialize. If |
| Type | type | The declared type to use for serializer lookup. This is typically the field or
property type rather than the runtime type of |
| IScyllaWriter | writer | The IScyllaWriter to which output is written. Must not be
|
| ISerializationContext | context | The current ISerializationContext providing settings and the
reference tracker. When non-null, its GetSerializer(Type)
is consulted first (allowing per-settings custom serializers to take precedence);
if it returns |
Exceptions
| Type | Condition |
|---|---|
| SerializationException | Thrown if no serializer can be found for |