Class TypeMetadata
Represents all reflection metadata required to serialize and deserialize a single C# type within the Scylla serialization system.
Inherited Members
Namespace: Scylla.Core.Util.Serialization
Assembly: ScyllaCore.dll
Syntax
public sealed class TypeMetadata
Remarks
TypeMetadata is constructed once per type and stored in the global TypeMetadataCache. Construction performs all expensive reflection operations - attribute scanning, property and field discovery, migration method lookup, and factory delegate compilation - so that subsequent serialization operations can work from pre-computed data with minimal overhead.
Instances are immutable and thread-safe after construction. They are safe to share across concurrent serialization contexts.
Member discovery rules:
- Public properties and fields are included by default unless decorated with ScyllaIgnoreAttribute.
- Non-public properties and fields are included only when decorated with ScyllaIncludeAttribute.
- Indexer properties and compiler-generated backing fields are always excluded.
Migration discovery rules: Static methods decorated with ScyllaMigrationAttribute that accept and return the declaring type are collected and indexed by version pair so the engine can apply them during deserialization of stale data.
Constructors
TypeMetadata(Type)
Initializes a new TypeMetadata instance by reflecting on all serialization-relevant aspects of the specified type.
Declaration
public TypeMetadata(Type type)
Parameters
| Type | Name | Description |
|---|---|---|
| Type | type | The Type to inspect. Must not be |
Exceptions
| Type | Condition |
|---|---|
| ArgumentNullException | Thrown if |
Properties
HasDefaultConstructor
Gets whether this type has a parameterless constructor (public or non-public) that can be used to create instances during deserialization.
Declaration
public bool HasDefaultConstructor { get; }
Property Value
| Type | Description |
|---|---|
| bool |
|
See Also
HasExplicitAlias
Gets whether the type declares an explicit, non-empty TypeAlias.
Declaration
public bool HasExplicitAlias { get; }
Property Value
| Type | Description |
|---|---|
| bool |
|
IsExplicitlySerializable
Gets whether this type is explicitly annotated with ScyllaSerializableAttribute.
Declaration
public bool IsExplicitlySerializable { get; }
Property Value
| Type | Description |
|---|---|
| bool |
|
IsNullable
Gets whether this type is a Nullable<T> wrapper around a value type.
Declaration
public bool IsNullable { get; }
Property Value
| Type | Description |
|---|---|
| bool |
|
See Also
IsPrimitive
Gets whether this type is a CLR primitive (e.g., int, float,
bool, char).
Declaration
public bool IsPrimitive { get; }
Property Value
| Type | Description |
|---|---|
| bool |
|
IsValueType
Gets whether this type is a value type (struct, enum, or primitive).
Declaration
public bool IsValueType { get; }
Property Value
| Type | Description |
|---|---|
| bool |
|
Properties
Gets the ordered, read-only list of serializable PropertyMetadata entries discovered for this type.
Declaration
public IReadOnlyList<PropertyMetadata> Properties { get; }
Property Value
| Type | Description |
|---|---|
| IReadOnlyList<PropertyMetadata> | Members are sorted first by Order (ascending), then alphabetically by Name for members that share the same order value. The list is computed once during construction and is never modified afterwards. |
See Also
PropertyLookup
Gets a read-only dictionary that maps each serialized property name to its PropertyMetadata, enabling O(1) lookup during deserialization.
Declaration
public IReadOnlyDictionary<string, PropertyMetadata> PropertyLookup { get; }
Property Value
| Type | Description |
|---|---|
| IReadOnlyDictionary<string, PropertyMetadata> | Keys are the serialized names (i.e., Name), compared with ordinal string equality. The dictionary is built from Properties and is never modified after construction. |
See Also
Type
Gets the runtime Type that this metadata instance describes.
Declaration
public Type Type { get; }
Property Value
| Type | Description |
|---|---|
| Type | The same Type object passed to the constructor. Never |
TypeAlias
Gets the alias string registered for this type in the alias index of TypeMetadataCache.
Declaration
public string TypeAlias { get; }
Property Value
| Type | Description |
|---|---|
| string | The value of TypeAlias if one was
specified on the type; otherwise, FullName. The
FullName default is only an index key and is never written
to serialized output; see HasExplicitAlias and
TypeMarkerName for what is written to the |
See Also
TypeMarkerName
Gets the name written to the $type property for this type: the explicit alias
when HasExplicitAlias is true, otherwise the assembly-qualified
type name.
Declaration
public string TypeMarkerName { get; }
Property Value
| Type | Description |
|---|---|
| string | A non-empty string computed once at construction, so writing a type marker does not allocate. |
See Also
UnderlyingNullableType
Gets the underlying value type if this type is Nullable<T>;
otherwise, null.
Declaration
public Type UnderlyingNullableType { get; }
Property Value
| Type | Description |
|---|---|
| Type | The result of GetUnderlyingType(Type) for the
described type, or |
See Also
Version
Gets the schema version declared on this type via ScyllaSerializableAttribute,
or 0 if the type is not explicitly annotated.
Declaration
public int Version { get; }
Property Value
| Type | Description |
|---|---|
| int | A positive integer if the type carries ScyllaSerializableAttribute;
|
See Also
Methods
CreateInstance()
Creates and returns a new, zero-initialized instance of Type using the compiled factory delegate.
Declaration
public object CreateInstance()
Returns
| Type | Description |
|---|---|
| object | A freshly constructed object of Type. For value types, this is the default (zeroed) struct. For reference types, this is the object returned by invoking the parameterless constructor. |
Exceptions
| Type | Condition |
|---|---|
| InvalidOperationException | Thrown if HasDefaultConstructor is |
GetMigration(int, int)
Retrieves the static migration method that handles upgrading data from
fromVersion to toVersion.
Declaration
public MethodInfo GetMigration(int fromVersion, int toVersion)
Parameters
| Type | Name | Description |
|---|---|---|
| int | fromVersion | The source schema version of the serialized data being deserialized. |
| int | toVersion | The target schema version to migrate the data toward. This does not need to be the type's current Version; intermediate steps are valid. |
Returns
| Type | Description |
|---|---|
| MethodInfo | The MethodInfo for the migration method decorated with
|
See Also
GetProperties(bool)
Gets the ordered member list to serialize, optionally extended with non-public members.
Declaration
public IReadOnlyList<PropertyMetadata> GetProperties(bool includePrivate)
Parameters
| Type | Name | Description |
|---|---|---|
| bool | includePrivate |
|
Returns
| Type | Description |
|---|---|
| IReadOnlyList<PropertyMetadata> | The ordered members. The list is cached and never modified. |
GetProperty(string)
Retrieves the PropertyMetadata for the member whose serialized name matches the specified string.
Declaration
public PropertyMetadata GetProperty(string name)
Parameters
| Type | Name | Description |
|---|---|---|
| string | name | The serialized property name (i.e., the key as it appears in the JSON output) to look up. The comparison is ordinal and case-sensitive. |
Returns
| Type | Description |
|---|---|
| PropertyMetadata | The matching PropertyMetadata instance if found in
PropertyLookup; otherwise, |
See Also
GetPropertyLookup(bool)
Gets the name lookup that matches GetProperties(bool) for the same argument.
Declaration
public IReadOnlyDictionary<string, PropertyMetadata> GetPropertyLookup(bool includePrivate)
Parameters
| Type | Name | Description |
|---|---|---|
| bool | includePrivate |
|
Returns
| Type | Description |
|---|---|
| IReadOnlyDictionary<string, PropertyMetadata> | The lookup keyed by serialized name. It is cached and never modified. |
HasMigrationPath(int, int)
Determines whether a complete migration path exists from fromVersion
to toVersion using the available ScyllaMigrationAttribute-
decorated methods.
Declaration
public bool HasMigrationPath(int fromVersion, int toVersion)
Parameters
| Type | Name | Description |
|---|---|---|
| int | fromVersion | The source schema version. If this is greater than or equal to
|
| int | toVersion | The target schema version to reach. Typically the type's current Version. |
Returns
| Type | Description |
|---|---|
| bool |
|
Remarks
Delegates to TryBuildMigrationPath(int, int, out IReadOnlyList<MethodInfo>), discarding the resolved path. Prefer TryBuildMigrationPath(int, int, out IReadOnlyList<MethodInfo>) directly when the caller is about to apply the migration anyway, so the path is not searched twice.
See Also
TryBuildMigrationPath(int, int, out IReadOnlyList<MethodInfo>)
Attempts to resolve the ordered sequence of ScyllaMigrationAttribute-
decorated migration methods that upgrades data from fromVersion
to toVersion, including a direct multi-version jump (e.g.
[ScyllaMigration(1, 3)]) as well as chains of single-version steps.
Declaration
public bool TryBuildMigrationPath(int fromVersion, int toVersion, out IReadOnlyList<MethodInfo> path)
Parameters
| Type | Name | Description |
|---|---|---|
| int | fromVersion | The source schema version of the serialized data. |
| int | toVersion | The target schema version to reach. |
| IReadOnlyList<MethodInfo> | path | On success, the ordered list of migration methods to invoke in sequence, starting
from |
Returns
| Type | Description |
|---|---|
| bool |
|
Remarks
The path is found via a breadth-first search over the migration graph, treating
each registered (from, to) pair as a directed edge. Breadth-first search
guarantees the shortest hop count, so a direct multi-version migration is
preferred over a needlessly long chain of single-version steps when both exist
for the same version gap.
The result is cached per (fromVersion, toVersion) pair, including a
cached "no path exists" result, so a version gap is searched at most once per
type rather than once per deserialize call.