Skip to main content
Prowl.Echo controls serialization behaviour through a set of declarative attributes. Most of these attributes live on fields and tell the serializer whether to include or skip a field, how to handle its name across data migrations, and under what conditions it should be written. One attribute — [GenerateSerializer] — operates at the type level and triggers source generation of a complete ISerializable implementation. A second type-level attribute, [FixedEchoStructure], switches a type to positional (index-based) serialization for maximum compactness and speed.

[GenerateSerializer]

Marks a partial class or struct for automatic source-generated ISerializable implementation. The source generator reads the type’s fields at compile time and emits optimized Serialize and Deserialize methods, taking all other Echo attributes into account.
The generator is bundled in the Prowl.Echo NuGet package — no separate analyzer package reference is required. The type must be declared partial for the generator to emit code alongside it.
The source generator is under active development. Always review the generated output, especially for complex types with inheritance, generics, or unusual field patterns.

Usage

The generator produces the Serialize and Deserialize methods in a separate partial file at build time. You never need to write them by hand.

[FixedEchoStructure]

Marks a type for positional (ordinal) serialization. Instead of a named Compound ({"x": 1.0, "y": 2.0, "z": 3.0}), the type is serialized as an ordered List ([1.0, 2.0, 3.0]). This eliminates field-name overhead entirely, making it ideal for hot-path types like math primitives and network packets.
The field order must never change. Because values are stored by position rather than name, reordering, inserting, or removing fields will silently corrupt all existing serialized data. Only apply this attribute to types whose layout is truly stable.
[FixedEchoStructure] works especially well for types like Vector3, Quaternion, Color, and fixed-size network messages — types where you fully control the schema and can guarantee it will not evolve.

Usage


[SerializeField]

Forces a private or protected field to be included in serialization. By default, Echo only serializes public fields; [SerializeField] opts a non-public field into that set without changing its access modifier.

Usage


[SerializeIgnore]

Excludes a public field from serialization. The effect is identical to marking the field with [System.NonSerialized] — both annotations cause Echo to skip the field entirely. Use [SerializeIgnore] when you want the exclusion to be expressed in Echo’s own vocabulary rather than the BCL’s attribute.

Usage


[FormerlySerializedAs]

Maps one or more legacy field names to the current field name during deserialization. When Echo reads a compound and cannot find the current field name, it checks whether any [FormerlySerializedAs] annotation matches a key that does exist in the stored data, and reads from that key instead. AllowMultiple = true means you can stack the attribute to support an arbitrary chain of historical renames.
[FormerlySerializedAs] only affects deserialization. Serialization always writes the current field name.

Properties

string
The historical name that was used in previously serialized data.

Usage


[IgnoreOnNull]

Skips writing a field to the output when its value is null. Without this attribute, a null field is written as an explicit null entry in the compound. With it, the key is omitted entirely, which reduces the size of the serialized output for sparsely-populated objects.
[IgnoreOnNull] pairs well with optional reference fields — configuration overrides, plugin extensions, or nullable metadata — where the absence of a value is the common case and the default is restored on deserialization without any stored entry.

Usage


[SerializeIf]

Conditionally includes or excludes a field based on the runtime value of another member on the same type. The named member must return bool; it can be a field, a property, or a parameterless method. When the condition member evaluates to false at serialization time, the field is skipped.
[SerializeIf] is evaluated only during serialization, not during deserialization. If the condition was false when data was written, the field simply will not be present in the stored compound.

Properties

string
The name of the field, property, or method on the same type whose return value controls whether this field is serialized. The member must return bool.

Usage

You can also reference a computed property: