Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ProwlEngine/Prowl.Echo/llms.txt

Use this file to discover all available pages before exploring further.

Serializer is the primary entry point for all serialization and deserialization in Prowl.Echo. It is a static class that converts .NET objects to and from EchoObject, the library’s intermediate representation. Internally, Serializer maintains a prioritized list of ISerializationFormat handlers — from fast-path primitive formatters through to a universal AnyObjectFormat fallback — and routes each type to the first handler that claims it.

Properties

Logger
IEchoLogger
default:"NullEchoLogger"
The logger instance used by the serialization pipeline. Assign any implementation of IEchoLogger to capture diagnostics. Defaults to NullEchoLogger, which discards all messages.
Serializer.Logger = new MyCustomLogger();

Serialize

Four overloads cover every combination of explicit target type and explicit SerializationContext. When no SerializationContext is supplied, a new one is created internally with the given TypeMode.

Serialize(object?, TypeMode)

public static EchoObject Serialize(object? value, TypeMode typeMode = TypeMode.Auto)
Serializes value using a freshly created SerializationContext. Because no declared target type is provided, the root object is always wrapped with type information in Auto mode so it can be round-tripped without the caller knowing the concrete type.
value
object?
The object to serialize. Passing null returns an EchoObject with TagType == EchoType.Null.
typeMode
TypeMode
default:"TypeMode.Auto"
Controls when type metadata is embedded. See the TypeMode reference.
Returns — An EchoObject representing the serialized form of value.
var player = new Player { Name = "Ada", Score = 9000 };
EchoObject echo = Serializer.Serialize(player);

Serialize(Type?, object?, TypeMode)

public static EchoObject Serialize(Type? targetType, object? value, TypeMode typeMode = TypeMode.Auto)
Serializes value treating targetType as the statically-declared type. Type metadata is only embedded when value’s runtime type differs from targetType (in Auto mode), enabling polymorphic fields to be round-tripped while keeping the output compact for non-polymorphic ones.
targetType
Type?
The declared/expected type at the call site. Pass null to let the serializer infer it from the value’s runtime type.
value
object?
The object to serialize.
typeMode
TypeMode
default:"TypeMode.Auto"
Controls when type metadata is embedded.
Returns — An EchoObject representing the serialized form of value.
// Serialize a concrete Sword as its base IWeapon interface — type info is embedded
// because Sword != IWeapon.
EchoObject echo = Serializer.Serialize(typeof(IWeapon), new Sword(), TypeMode.Auto);

Serialize(object?, SerializationContext)

public static EchoObject Serialize(object? value, SerializationContext context)
Serializes value using a caller-supplied SerializationContext. Reuse the same context across multiple calls when you need shared reference-tracking state (for example, when serializing an entire scene graph in one pass).
value
object?
The object to serialize.
context
SerializationContext
The serialization context. Its OnSerialize hook is invoked before any built-in formatter runs, and its TypeMode governs type-metadata embedding.
Returns — An EchoObject representing the serialized form of value.
var ctx = new SerializationContext(TypeMode.Aggressive);
EchoObject echoA = Serializer.Serialize(objA, ctx);
EchoObject echoB = Serializer.Serialize(objB, ctx); // shares reference table with echoA

Serialize(Type?, object?, SerializationContext)

public static EchoObject Serialize(Type? targetType, object? value, SerializationContext context)
The most explicit overload — combines a declared target type with a caller-supplied context. All other Serialize overloads ultimately call this one.
targetType
Type?
The declared/expected type at the call site.
value
object?
The object to serialize.
context
SerializationContext
The serialization context.
Returns — An EchoObject representing the serialized form of value.
If value is itself already an EchoObject, it is returned as-is without any further processing.

Deserialize

All Deserialize overloads mirror the Serialize overloads. When no SerializationContext is provided, a default one is created internally.

Deserialize<T>(EchoObject?)

public static T? Deserialize<T>(EchoObject? value)
Deserializes value into type T using a default context.
value
EchoObject?
The EchoObject to deserialize. Returns the default value of T when null or EchoType.Null.
Returns — An instance of T, or null/default if value is null or empty.
Player? player = Serializer.Deserialize<Player>(echo);

Deserialize(EchoObject?, Type)

public static object? Deserialize(EchoObject? value, Type targetType)
Non-generic overload; useful when the target type is only known at runtime.
value
EchoObject?
The EchoObject to deserialize.
targetType
Type
The type to deserialize into.
Returns — A boxed instance of targetType, or null.
object? obj = Serializer.Deserialize(echo, typeof(Player));

Deserialize<T>(EchoObject?, SerializationContext)

public static T? Deserialize<T>(EchoObject? value, SerializationContext context)
Generic deserialization with an explicit context. Use this when the context carries OnDeserialize hooks or was previously used during serialization and holds a populated reference table.
value
EchoObject?
The EchoObject to deserialize.
context
SerializationContext
The deserialization context. Its OnDeserialize hook is invoked before any built-in formatter runs.
Returns — An instance of T, or null/default.

Deserialize(EchoObject?, Type, SerializationContext)

public static object? Deserialize(EchoObject? value, Type targetType, SerializationContext context)
The most explicit deserialization overload. All other Deserialize overloads call this one.
value
EchoObject?
The EchoObject to deserialize.
targetType
Type
The target type.
context
SerializationContext
The deserialization context.
Returns — A boxed instance of targetType, or null.
If the EchoObject contains embedded type metadata (a $type key), the serializer resolves the actual type from that metadata and uses it instead of targetType. This enables transparent polymorphic deserialization.

DeserializeInto

DeserializeInto writes deserialized field values into an existing object instance instead of constructing a new one. This is valuable when the target object holds non-serialized state — GPU resources, history buffers, caches — that should not be discarded during a hot-reload or network update.
DeserializeInto only works for compound/object types processed by AnyObjectFormat. Primitive types, arrays, and collections are not supported.

DeserializeInto(EchoObject?, object)

public static void DeserializeInto(EchoObject? value, object target)
value
EchoObject?
The serialized data to read from. No-op when null or EchoType.Null.
target
object
The existing object whose fields will be overwritten. Must not be null.
// Re-use an existing Player instance to preserve its internal event subscriptions.
Serializer.DeserializeInto(savedEcho, existingPlayer);

DeserializeInto(EchoObject?, object, SerializationContext)

public static void DeserializeInto(EchoObject? value, object target, SerializationContext context)
value
EchoObject?
The serialized data to read from.
target
object
The existing object whose fields will be overwritten.
context
SerializationContext
The deserialization context, including any OnDeserialize hooks.

Format Management

RegisterFormat(ISerializationFormat)

public static void RegisterFormat(ISerializationFormat format)
Registers a custom serialization format with the highest priority. The new format is inserted at the front of the handler list, ahead of all built-in formatters, but always before the AnyObjectFormat fallback which remains last. Calling RegisterFormat automatically clears the internal format cache so the new handler is consulted on the next serialization operation for each type.
format
ISerializationFormat
The custom format to register. Its CanHandle(Type) method determines which types it intercepts.
public class MyVectorFormat : ISerializationFormat
{
    public bool CanHandle(Type type) => type == typeof(Vector3);

    public EchoObject Serialize(Type type, object value, SerializationContext ctx)
    {
        var v = (Vector3)value;
        var tag = EchoObject.NewCompound();
        tag["x"] = new EchoObject(v.X);
        tag["y"] = new EchoObject(v.Y);
        tag["z"] = new EchoObject(v.Z);
        return tag;
    }

    public object Deserialize(EchoObject data, Type type, SerializationContext ctx)
    {
        return new Vector3(
            data["x"].FloatValue,
            data["y"].FloatValue,
            data["z"].FloatValue);
    }
}

Serializer.RegisterFormat(new MyVectorFormat());

ClearCache()

public static void ClearCache()
Clears the internal format-selection cache, all reflection caches held by ReflectionUtils, and the type-name lookup cache in TypeNameRegistry. Call this after dynamically loading or unloading assemblies to ensure the serializer picks up new or removed types.
// After a plugin assembly is loaded at runtime:
AssemblyLoadContext.Default.LoadFromAssemblyPath(pluginPath);
Serializer.ClearCache();
Under normal usage you never need to call ClearCache(). It is primarily intended for plugin/hot-reload scenarios.

Common Usage Patterns

Basic round-trip

// Serialize
EchoObject echo = Serializer.Serialize(myObject);

// Persist to binary
echo.WriteToBinary(new FileInfo("save.bin"));

// Load and deserialize
EchoObject loaded = EchoObject.ReadFromBinary(new FileInfo("save.bin"));
MyClass restored = Serializer.Deserialize<MyClass>(loaded)!;

Polymorphic collection with TypeMode.Aggressive

List<IShape> shapes = new() { new Circle(5f), new Rectangle(3f, 4f) };

var ctx = new SerializationContext(TypeMode.Aggressive);
EchoObject echo = Serializer.Serialize(typeof(List<IShape>), shapes, ctx);

var ctx2 = new SerializationContext(TypeMode.Aggressive);
var restored = Serializer.Deserialize<List<IShape>>(echo, ctx2);

Hot-reload into existing instance

// Preserve the camera's render pipeline while refreshing its data fields.
EchoObject freshData = EchoObject.ReadFromString(liveConfigString);
Serializer.DeserializeInto(freshData, existingCamera);

Build docs developers (and LLMs) love