This is an automated email from the ASF dual-hosted git repository.
chaokunyang pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/fory.git
The following commit(s) were added to refs/heads/main by this push:
new c8fd5ed5c refactor(c#): refactor serializer interface to minimize API
surface (#3403)
c8fd5ed5c is described below
commit c8fd5ed5c3d463e5bdb772553a21d2ec4789af03
Author: Shawn Yang <[email protected]>
AuthorDate: Wed Feb 25 02:15:12 2026 +0800
refactor(c#): refactor serializer interface to minimize API surface (#3403)
## Why?
`Serializer<T>` had accumulated type metadata and object-dispatch
responsibilities (type id, nullability, ref-tracking, type-info
read/write, and object-level read/write). That expanded the public
serializer API and duplicated logic across many serializer
implementations.
## What does this PR do?
- Removes the non-generic `Serializer` base and narrows `Serializer<T>`
to typed read/write responsibilities.
- Introduces richer `TypeInfo` metadata (built-in/user/dynamic kind,
nullability, ref-trackability, default object, object-level read/write
delegates, and field type-info decisions).
- Refactors `TypeResolver` to operate on `TypeInfo` for registration,
serializer factory creation/validation, wire-type resolution, and
centralized type-info read/write.
- Updates collection/dictionary/nullable-key/Any serialization flows and
generator output to use `TypeInfo` + resolver-dispatched
object/type-info operations.
- Removes repeated `StaticTypeId`/nullability/ref-tracking/`IsNone`
overrides across primitive, array, collection, dictionary, optional,
string, time, enum, and union serializers.
- Updates C# registration and peer test serializer call sites to the new
type-info driven serializer contract.
## Related issues
## Does this PR introduce any user-facing change?
- [x] Does this PR introduce any public API change?
- [ ] Does this PR introduce any binary protocol compatibility change?
## Benchmark
---
csharp/src/Fory.Generator/ForyObjectGenerator.cs | 14 +-
csharp/src/Fory/AnySerializer.cs | 41 +-
csharp/src/Fory/CollectionSerializers.cs | 61 +--
csharp/src/Fory/DictionarySerializers.cs | 61 +--
csharp/src/Fory/EnumSerializer.cs | 1 -
csharp/src/Fory/Fory.cs | 11 +-
csharp/src/Fory/NullableKeyDictionary.cs | 58 +--
csharp/src/Fory/OptionalSerializer.cs | 30 --
csharp/src/Fory/PrimitiveArraySerializers.cs | 50 ---
csharp/src/Fory/PrimitiveCollectionSerializers.cs | 135 ------
csharp/src/Fory/PrimitiveDictionarySerializers.cs | 20 -
csharp/src/Fory/PrimitiveSerializers.cs | 15 -
csharp/src/Fory/Serializer.cs | 130 +-----
csharp/src/Fory/StringSerializer.cs | 4 -
csharp/src/Fory/TimeSerializers.cs | 24 --
csharp/src/Fory/TypeId.cs | 19 -
csharp/src/Fory/TypeInfo.cs | 450 +++++++++++++++++++-
csharp/src/Fory/TypeResolver.cs | 492 ++++++++++++++--------
csharp/src/Fory/UnionSerializer.cs | 8 -
csharp/tests/Fory.XlangPeer/Program.cs | 4 -
20 files changed, 872 insertions(+), 756 deletions(-)
diff --git a/csharp/src/Fory.Generator/ForyObjectGenerator.cs
b/csharp/src/Fory.Generator/ForyObjectGenerator.cs
index 5d2cdb09a..808e6ef6b 100644
--- a/csharp/src/Fory.Generator/ForyObjectGenerator.cs
+++ b/csharp/src/Fory.Generator/ForyObjectGenerator.cs
@@ -135,7 +135,8 @@ public sealed class ForyObjectGenerator :
IIncrementalGenerator
private static void EmitObjectSerializer(StringBuilder sb, TypeModel model)
{
- sb.AppendLine($"file sealed class {model.SerializerName} :
global::Apache.Fory.Serializer<{model.TypeName}>");
+ sb.AppendLine(
+ $"file sealed class {model.SerializerName} :
global::Apache.Fory.Serializer<{model.TypeName}>");
sb.AppendLine("{");
foreach (MemberModel member in model.Members.Where(m =>
m.UseDictionaryTypeInfoCache))
{
@@ -306,13 +307,9 @@ public sealed class ForyObjectGenerator :
IIncrementalGenerator
sb.AppendLine(" return value;");
sb.AppendLine(" }");
sb.AppendLine();
- sb.AppendLine(" public override global::Apache.Fory.TypeId
StaticTypeId => global::Apache.Fory.TypeId.Struct;");
if (model.Kind == DeclKind.Class)
{
- sb.AppendLine(" public override bool IsNullableType => true;");
- sb.AppendLine(" public override bool IsReferenceTrackableType
=> true;");
sb.AppendLine($" public override {model.TypeName} DefaultValue
=> null!;");
- sb.AppendLine($" public override bool IsNone(in
{model.TypeName} value) => value is null;");
}
else
{
@@ -320,7 +317,7 @@ public sealed class ForyObjectGenerator :
IIncrementalGenerator
}
sb.AppendLine();
- sb.AppendLine(" public override
global::System.Collections.Generic.IReadOnlyList<global::Apache.Fory.TypeMetaFieldInfo>
CompatibleTypeMetaFields(bool trackRef)");
+ sb.AppendLine(" public
global::System.Collections.Generic.IReadOnlyList<global::Apache.Fory.TypeMetaFieldInfo>
CompatibleTypeMetaFields(bool trackRef)");
sb.AppendLine(" {");
if (model.SortedMembers.Length == 0)
{
@@ -438,7 +435,7 @@ public sealed class ForyObjectGenerator :
IIncrementalGenerator
string memberAccess = $"value.{member.Name}";
string hasGenerics = member.IsCollection ? "true" : "false";
string writeTypeInfo = compatibleMode
- ?
$"__ForyNeedsTypeInfoForField(context.TypeResolver.GetTypeInfo<{member.TypeName}>().StaticTypeId)"
+ ?
$"context.TypeResolver.GetTypeInfo<{member.TypeName}>().NeedsTypeInfoForField()"
: "false";
switch (member.DynamicAnyKind)
@@ -516,7 +513,8 @@ public sealed class ForyObjectGenerator :
IIncrementalGenerator
sb.AppendLine($" __Fory{cacheId}DictRuntimeType =
{runtimeTypeVar};");
sb.AppendLine($" __Fory{cacheId}DictTypeInfo =
{typeInfoVar};");
sb.AppendLine(" }");
- sb.AppendLine($" {typeInfoVar}.WriteObject(context,
{fieldValueVar}, {refModeExpr}, {writeTypeInfo}, {hasGenerics});");
+ sb.AppendLine(
+ $" context.TypeResolver.WriteObject({typeInfoVar},
context, {fieldValueVar}, {refModeExpr}, {writeTypeInfo}, {hasGenerics});");
sb.AppendLine(" }");
}
diff --git a/csharp/src/Fory/AnySerializer.cs b/csharp/src/Fory/AnySerializer.cs
index 30df97111..77b6e80b2 100644
--- a/csharp/src/Fory/AnySerializer.cs
+++ b/csharp/src/Fory/AnySerializer.cs
@@ -19,15 +19,11 @@ namespace Apache.Fory;
public sealed class DynamicAnyObjectSerializer : Serializer<object?>
{
- public override TypeId StaticTypeId => TypeId.Unknown;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override object? DefaultValue => null;
- public override bool IsNone(in object? value) => value is null;
public override void WriteData(WriteContext context, in object? value,
bool hasGenerics)
{
- if (IsNone(value))
+ if (value is null)
{
return;
}
@@ -46,22 +42,11 @@ public sealed class DynamicAnyObjectSerializer :
Serializer<object?>
return context.TypeResolver.ReadDynamicValue(dynamicTypeInfo, context);
}
- public override void WriteTypeInfo(WriteContext context)
- {
- throw new InvalidDataException("dynamic Any value type info is
runtime-only");
- }
-
- public override void ReadTypeInfo(ReadContext context)
- {
- DynamicTypeInfo typeInfo =
context.TypeResolver.ReadDynamicTypeInfo(context);
- context.SetDynamicTypeInfo(typeof(object), typeInfo);
- }
-
public override void Write(WriteContext context, in object? value, RefMode
refMode, bool writeTypeInfo, bool hasGenerics)
{
if (refMode != RefMode.None)
{
- if (IsNone(value))
+ if (value is null)
{
context.Writer.WriteInt8((sbyte)RefFlag.Null);
return;
@@ -113,7 +98,7 @@ public sealed class DynamicAnyObjectSerializer :
Serializer<object?>
context.RefReader.PushPendingReference(reservedRefId);
if (readTypeInfo)
{
- ReadTypeInfo(context);
+ ReadAnyTypeInfo(context);
}
object? value = ReadData(context);
@@ -135,7 +120,7 @@ public sealed class DynamicAnyObjectSerializer :
Serializer<object?>
if (readTypeInfo)
{
- ReadTypeInfo(context);
+ ReadAnyTypeInfo(context);
}
object? result = ReadData(context);
@@ -149,8 +134,14 @@ public sealed class DynamicAnyObjectSerializer :
Serializer<object?>
private static bool AnyValueIsReferenceTrackable(object value,
TypeResolver typeResolver)
{
- Serializer serializer = typeResolver.GetSerializer(value.GetType());
- return serializer.IsReferenceTrackableType;
+ TypeInfo typeInfo = typeResolver.GetTypeInfo(value.GetType());
+ return typeInfo.IsReferenceTrackableType;
+ }
+
+ private static void ReadAnyTypeInfo(ReadContext context)
+ {
+ DynamicTypeInfo typeInfo =
context.TypeResolver.ReadDynamicTypeInfo(context);
+ context.SetDynamicTypeInfo(typeof(object), typeInfo);
}
}
@@ -169,8 +160,8 @@ public static class DynamicAnyCodec
return;
}
- Serializer serializer =
context.TypeResolver.GetSerializer(value.GetType());
- serializer.WriteTypeInfo(context);
+ TypeInfo typeInfo = context.TypeResolver.GetTypeInfo(value.GetType());
+ context.TypeResolver.WriteTypeInfo(typeInfo, context);
}
public static object? CastAnyDynamicValue(object? value, Type targetType)
@@ -220,8 +211,8 @@ public static class DynamicAnyCodec
return;
}
- Serializer serializer =
context.TypeResolver.GetSerializer(value.GetType());
- serializer.WriteDataObject(context, value, hasGenerics);
+ TypeInfo typeInfo = context.TypeResolver.GetTypeInfo(value.GetType());
+ context.TypeResolver.WriteDataObject(typeInfo, context, value,
hasGenerics);
}
private static bool TryWriteKnownTypeInfo(object value, WriteContext
context)
diff --git a/csharp/src/Fory/CollectionSerializers.cs
b/csharp/src/Fory/CollectionSerializers.cs
index e5130c02c..5b1a04068 100644
--- a/csharp/src/Fory/CollectionSerializers.cs
+++ b/csharp/src/Fory/CollectionSerializers.cs
@@ -31,9 +31,14 @@ internal static class CollectionBits
internal static class CollectionCodec
{
- private static bool CanDeclareElementType<T>(TypeId staticTypeId)
+ private static bool CanDeclareElementType<T>(TypeInfo typeInfo)
{
- if (!staticTypeId.NeedsTypeInfoForField())
+ if (typeInfo.IsBuiltinType)
+ {
+ return true;
+ }
+
+ if (!typeInfo.NeedsTypeInfoForField())
{
return true;
}
@@ -47,6 +52,7 @@ internal static class CollectionCodec
WriteContext context,
bool hasGenerics)
{
+ TypeInfo elementTypeInfo = context.TypeResolver.GetTypeInfo<T>();
List<T> list = values as List<T> ?? [.. values];
context.Writer.WriteVarUInt32((uint)list.Count);
if (list.Count == 0)
@@ -55,11 +61,11 @@ internal static class CollectionCodec
}
bool hasNull = false;
- if (elementSerializer.IsNullableType)
+ if (elementTypeInfo.IsNullableType)
{
for (int i = 0; i < list.Count; i++)
{
- if (!elementSerializer.IsNoneObject(list[i]))
+ if (!context.TypeResolver.IsNoneObject(elementTypeInfo,
list[i]))
{
continue;
}
@@ -69,9 +75,9 @@ internal static class CollectionCodec
}
}
- bool trackRef = context.TrackRef &&
elementSerializer.IsReferenceTrackableType;
- bool declaredElementType = hasGenerics &&
CanDeclareElementType<T>(elementSerializer.StaticTypeId);
- bool dynamicElementType = elementSerializer.StaticTypeId ==
TypeId.Unknown;
+ bool trackRef = context.TrackRef &&
elementTypeInfo.IsReferenceTrackableType;
+ bool declaredElementType = hasGenerics &&
CanDeclareElementType<T>(elementTypeInfo);
+ bool dynamicElementType = elementTypeInfo.IsDynamicType;
byte header = dynamicElementType ? (byte)0 : CollectionBits.SameType;
if (trackRef)
@@ -92,7 +98,7 @@ internal static class CollectionCodec
context.Writer.WriteUInt8(header);
if (!dynamicElementType && !declaredElementType)
{
- elementSerializer.WriteTypeInfo(context);
+ context.TypeResolver.WriteTypeInfo(elementSerializer, context);
}
if (dynamicElementType)
@@ -120,7 +126,7 @@ internal static class CollectionCodec
{
foreach (T element in list)
{
- if (elementSerializer.IsNoneObject(element))
+ if (context.TypeResolver.IsNoneObject(elementTypeInfo,
element))
{
context.Writer.WriteInt8((sbyte)RefFlag.Null);
}
@@ -142,6 +148,7 @@ internal static class CollectionCodec
public static List<T> ReadCollectionData<T>(Serializer<T>
elementSerializer, ReadContext context)
{
+ TypeInfo elementTypeInfo = context.TypeResolver.GetTypeInfo<T>();
int length = checked((int)context.Reader.ReadVarUInt32());
if (length == 0)
{
@@ -153,7 +160,7 @@ internal static class CollectionCodec
bool hasNull = (header & CollectionBits.HasNull) != 0;
bool declared = (header & CollectionBits.DeclaredElementType) != 0;
bool sameType = (header & CollectionBits.SameType) != 0;
- bool canonicalizeElements = context.TrackRef && !trackRef &&
elementSerializer.IsReferenceTrackableType;
+ bool canonicalizeElements = context.TrackRef && !trackRef &&
elementTypeInfo.IsReferenceTrackableType;
List<T> values = new(length);
if (!sameType)
@@ -200,7 +207,7 @@ internal static class CollectionCodec
if (!declared)
{
- elementSerializer.ReadTypeInfo(context);
+ context.TypeResolver.ReadTypeInfo(elementSerializer, context);
}
if (trackRef)
@@ -481,11 +488,7 @@ internal static class DynamicContainerCodec
public sealed class ArraySerializer<T> : Serializer<T[]>
{
- public override TypeId StaticTypeId => TypeId.List;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override T[] DefaultValue => null!;
- public override bool IsNone(in T[] value) => value is null;
public override void WriteData(WriteContext context, in T[] value, bool
hasGenerics)
{
@@ -506,11 +509,7 @@ public sealed class ArraySerializer<T> : Serializer<T[]>
public class ListSerializer<T> : Serializer<List<T>>
{
- public override TypeId StaticTypeId => TypeId.List;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override List<T> DefaultValue => null!;
- public override bool IsNone(in List<T> value) => value is null;
public override void WriteData(WriteContext context, in List<T> value,
bool hasGenerics)
{
@@ -526,11 +525,7 @@ public class ListSerializer<T> : Serializer<List<T>>
public sealed class SetSerializer<T> : Serializer<HashSet<T>> where T : notnull
{
- public override TypeId StaticTypeId => TypeId.Set;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override HashSet<T> DefaultValue => null!;
- public override bool IsNone(in HashSet<T> value) => value is null;
public override void WriteData(WriteContext context, in HashSet<T> value,
bool hasGenerics)
{
@@ -546,11 +541,7 @@ public sealed class SetSerializer<T> :
Serializer<HashSet<T>> where T : notnull
public sealed class SortedSetSerializer<T> : Serializer<SortedSet<T>> where T
: notnull
{
- public override TypeId StaticTypeId => TypeId.Set;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override SortedSet<T> DefaultValue => null!;
- public override bool IsNone(in SortedSet<T> value) => value is null;
public override void WriteData(WriteContext context, in SortedSet<T>
value, bool hasGenerics)
{
@@ -566,11 +557,7 @@ public sealed class SortedSetSerializer<T> :
Serializer<SortedSet<T>> where T :
public sealed class ImmutableHashSetSerializer<T> :
Serializer<ImmutableHashSet<T>> where T : notnull
{
- public override TypeId StaticTypeId => TypeId.Set;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override ImmutableHashSet<T> DefaultValue => null!;
- public override bool IsNone(in ImmutableHashSet<T> value) => value is null;
public override void WriteData(WriteContext context, in
ImmutableHashSet<T> value, bool hasGenerics)
{
@@ -586,11 +573,7 @@ public sealed class ImmutableHashSetSerializer<T> :
Serializer<ImmutableHashSet<
public sealed class LinkedListSerializer<T> : Serializer<LinkedList<T>>
{
- public override TypeId StaticTypeId => TypeId.List;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override LinkedList<T> DefaultValue => null!;
- public override bool IsNone(in LinkedList<T> value) => value is null;
public override void WriteData(WriteContext context, in LinkedList<T>
value, bool hasGenerics)
{
@@ -606,11 +589,7 @@ public sealed class LinkedListSerializer<T> :
Serializer<LinkedList<T>>
public sealed class QueueSerializer<T> : Serializer<Queue<T>>
{
- public override TypeId StaticTypeId => TypeId.List;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override Queue<T> DefaultValue => null!;
- public override bool IsNone(in Queue<T> value) => value is null;
public override void WriteData(WriteContext context, in Queue<T> value,
bool hasGenerics)
{
@@ -633,11 +612,7 @@ public sealed class QueueSerializer<T> :
Serializer<Queue<T>>
public sealed class StackSerializer<T> : Serializer<Stack<T>>
{
- public override TypeId StaticTypeId => TypeId.List;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override Stack<T> DefaultValue => null!;
- public override bool IsNone(in Stack<T> value) => value is null;
public override void WriteData(WriteContext context, in Stack<T> value,
bool hasGenerics)
{
diff --git a/csharp/src/Fory/DictionarySerializers.cs
b/csharp/src/Fory/DictionarySerializers.cs
index 703526767..289435549 100644
--- a/csharp/src/Fory/DictionarySerializers.cs
+++ b/csharp/src/Fory/DictionarySerializers.cs
@@ -33,11 +33,7 @@ public abstract class DictionaryLikeSerializer<TDictionary,
TKey, TValue> : Seri
where TDictionary : class, IDictionary<TKey, TValue>
where TKey : notnull
{
- public override TypeId StaticTypeId => TypeId.Map;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override TDictionary DefaultValue => null!;
- public override bool IsNone(in TDictionary value) => value is null;
protected abstract TDictionary CreateMap(int capacity);
@@ -55,6 +51,8 @@ public abstract class DictionaryLikeSerializer<TDictionary,
TKey, TValue> : Seri
{
Serializer<TKey> keySerializer =
context.TypeResolver.GetSerializer<TKey>();
Serializer<TValue> valueSerializer =
context.TypeResolver.GetSerializer<TValue>();
+ TypeInfo keyTypeInfo = context.TypeResolver.GetTypeInfo<TKey>();
+ TypeInfo valueTypeInfo = context.TypeResolver.GetTypeInfo<TValue>();
TDictionary map = value ?? CreateMap(0);
context.Writer.WriteVarUInt32((uint)map.Count);
if (map.Count == 0)
@@ -62,12 +60,12 @@ public abstract class DictionaryLikeSerializer<TDictionary,
TKey, TValue> : Seri
return;
}
- bool trackKeyRef = context.TrackRef &&
keySerializer.IsReferenceTrackableType;
- bool trackValueRef = context.TrackRef &&
valueSerializer.IsReferenceTrackableType;
- bool keyDeclared = hasGenerics &&
!keySerializer.StaticTypeId.NeedsTypeInfoForField();
- bool valueDeclared = hasGenerics &&
!valueSerializer.StaticTypeId.NeedsTypeInfoForField();
- bool keyDynamicType = keySerializer.StaticTypeId == TypeId.Unknown;
- bool valueDynamicType = valueSerializer.StaticTypeId == TypeId.Unknown;
+ bool trackKeyRef = context.TrackRef &&
keyTypeInfo.IsReferenceTrackableType;
+ bool trackValueRef = context.TrackRef &&
valueTypeInfo.IsReferenceTrackableType;
+ bool keyDeclared = hasGenerics && !keyTypeInfo.NeedsTypeInfoForField();
+ bool valueDeclared = hasGenerics &&
!valueTypeInfo.NeedsTypeInfoForField();
+ bool keyDynamicType = keyTypeInfo.IsDynamicType;
+ bool valueDynamicType = valueTypeInfo.IsDynamicType;
KeyValuePair<TKey, TValue>[] pairs = SnapshotPairs(map);
if (keyDynamicType || valueDynamicType)
@@ -82,6 +80,8 @@ public abstract class DictionaryLikeSerializer<TDictionary,
TKey, TValue> : Seri
valueDeclared,
keyDynamicType,
valueDynamicType,
+ keyTypeInfo,
+ valueTypeInfo,
keySerializer,
valueSerializer);
return;
@@ -91,8 +91,8 @@ public abstract class DictionaryLikeSerializer<TDictionary,
TKey, TValue> : Seri
while (index < pairs.Length)
{
KeyValuePair<TKey, TValue> pair = pairs[index];
- bool keyIsNull = keySerializer.IsNoneObject(pair.Key);
- bool valueIsNull = valueSerializer.IsNoneObject(pair.Value);
+ bool keyIsNull = context.TypeResolver.IsNoneObject(keyTypeInfo,
pair.Key);
+ bool valueIsNull =
context.TypeResolver.IsNoneObject(valueTypeInfo, pair.Value);
if (keyIsNull || valueIsNull)
{
byte header = 0;
@@ -131,7 +131,7 @@ public abstract class DictionaryLikeSerializer<TDictionary,
TKey, TValue> : Seri
{
if (!keyDeclared)
{
- keySerializer.WriteTypeInfo(context);
+ context.TypeResolver.WriteTypeInfo(keySerializer,
context);
}
keySerializer.Write(context, pair.Key, trackKeyRef ?
RefMode.Tracking : RefMode.None, false, hasGenerics);
@@ -141,7 +141,7 @@ public abstract class DictionaryLikeSerializer<TDictionary,
TKey, TValue> : Seri
{
if (!valueDeclared)
{
- valueSerializer.WriteTypeInfo(context);
+ context.TypeResolver.WriteTypeInfo(valueSerializer,
context);
}
valueSerializer.Write(context, pair.Value, trackValueRef ?
RefMode.Tracking : RefMode.None, false, hasGenerics);
@@ -177,19 +177,20 @@ public abstract class
DictionaryLikeSerializer<TDictionary, TKey, TValue> : Seri
context.Writer.WriteUInt8(0);
if (!keyDeclared)
{
- keySerializer.WriteTypeInfo(context);
+ context.TypeResolver.WriteTypeInfo(keySerializer, context);
}
if (!valueDeclared)
{
- valueSerializer.WriteTypeInfo(context);
+ context.TypeResolver.WriteTypeInfo(valueSerializer, context);
}
byte chunkSize = 0;
while (index < pairs.Length && chunkSize < byte.MaxValue)
{
KeyValuePair<TKey, TValue> current = pairs[index];
- if (keySerializer.IsNoneObject(current.Key) ||
valueSerializer.IsNoneObject(current.Value))
+ if (context.TypeResolver.IsNoneObject(keyTypeInfo,
current.Key) ||
+ context.TypeResolver.IsNoneObject(valueTypeInfo,
current.Value))
{
break;
}
@@ -208,6 +209,8 @@ public abstract class DictionaryLikeSerializer<TDictionary,
TKey, TValue> : Seri
{
Serializer<TKey> keySerializer =
context.TypeResolver.GetSerializer<TKey>();
Serializer<TValue> valueSerializer =
context.TypeResolver.GetSerializer<TValue>();
+ TypeInfo keyTypeInfo = context.TypeResolver.GetTypeInfo<TKey>();
+ TypeInfo valueTypeInfo = context.TypeResolver.GetTypeInfo<TValue>();
int totalLength = checked((int)context.Reader.ReadVarUInt32());
if (totalLength == 0)
{
@@ -215,9 +218,9 @@ public abstract class DictionaryLikeSerializer<TDictionary,
TKey, TValue> : Seri
}
TDictionary map = CreateMap(totalLength);
- bool keyDynamicType = keySerializer.StaticTypeId == TypeId.Unknown;
- bool valueDynamicType = valueSerializer.StaticTypeId == TypeId.Unknown;
- bool canonicalizeValues = context.TrackRef &&
valueSerializer.IsReferenceTrackableType;
+ bool keyDynamicType = keyTypeInfo.IsDynamicType;
+ bool valueDynamicType = valueTypeInfo.IsDynamicType;
+ bool canonicalizeValues = context.TrackRef &&
valueTypeInfo.IsReferenceTrackableType;
int readCount = 0;
while (readCount < totalLength)
@@ -280,7 +283,7 @@ public abstract class DictionaryLikeSerializer<TDictionary,
TKey, TValue> : Seri
}
else
{
- keySerializer.ReadTypeInfo(context);
+ context.TypeResolver.ReadTypeInfo(keySerializer,
context);
}
}
@@ -292,7 +295,7 @@ public abstract class DictionaryLikeSerializer<TDictionary,
TKey, TValue> : Seri
}
else
{
- valueSerializer.ReadTypeInfo(context);
+ context.TypeResolver.ReadTypeInfo(valueSerializer,
context);
}
}
@@ -332,12 +335,12 @@ public abstract class
DictionaryLikeSerializer<TDictionary, TKey, TValue> : Seri
if (!keyDeclared)
{
- keySerializer.ReadTypeInfo(context);
+ context.TypeResolver.ReadTypeInfo(keySerializer, context);
}
if (!valueDeclared)
{
- valueSerializer.ReadTypeInfo(context);
+ context.TypeResolver.ReadTypeInfo(valueSerializer, context);
}
for (int i = 0; i < chunkSize; i++)
@@ -373,13 +376,15 @@ public abstract class
DictionaryLikeSerializer<TDictionary, TKey, TValue> : Seri
bool valueDeclared,
bool keyDynamicType,
bool valueDynamicType,
+ TypeInfo keyTypeInfo,
+ TypeInfo valueTypeInfo,
Serializer<TKey> keySerializer,
Serializer<TValue> valueSerializer)
{
foreach (KeyValuePair<TKey, TValue> pair in pairs)
{
- bool keyIsNull = keySerializer.IsNoneObject(pair.Key);
- bool valueIsNull = valueSerializer.IsNoneObject(pair.Value);
+ bool keyIsNull = context.TypeResolver.IsNoneObject(keyTypeInfo,
pair.Key);
+ bool valueIsNull =
context.TypeResolver.IsNoneObject(valueTypeInfo, pair.Value);
byte header = 0;
if (trackKeyRef)
{
@@ -446,7 +451,7 @@ public abstract class DictionaryLikeSerializer<TDictionary,
TKey, TValue> : Seri
}
else
{
- keySerializer.WriteTypeInfo(context);
+ context.TypeResolver.WriteTypeInfo(keySerializer, context);
}
}
@@ -458,7 +463,7 @@ public abstract class DictionaryLikeSerializer<TDictionary,
TKey, TValue> : Seri
}
else
{
- valueSerializer.WriteTypeInfo(context);
+ context.TypeResolver.WriteTypeInfo(valueSerializer,
context);
}
}
diff --git a/csharp/src/Fory/EnumSerializer.cs
b/csharp/src/Fory/EnumSerializer.cs
index e830f0756..a7cff943e 100644
--- a/csharp/src/Fory/EnumSerializer.cs
+++ b/csharp/src/Fory/EnumSerializer.cs
@@ -22,7 +22,6 @@ public sealed class EnumSerializer<TEnum> : Serializer<TEnum>
where TEnum : stru
private static readonly Dictionary<TEnum, uint> DefinedValueToOrdinal =
BuildValueToOrdinalMap();
private static readonly Dictionary<uint, TEnum> DefinedOrdinalToValue =
BuildOrdinalToValueMap(DefinedValueToOrdinal);
- public override TypeId StaticTypeId => TypeId.Enum;
public override TEnum DefaultValue => default;
public override void WriteData(WriteContext context, in TEnum value, bool
hasGenerics)
diff --git a/csharp/src/Fory/Fory.cs b/csharp/src/Fory/Fory.cs
index d70cef7dd..412c17c61 100644
--- a/csharp/src/Fory/Fory.cs
+++ b/csharp/src/Fory/Fory.cs
@@ -80,16 +80,16 @@ public sealed class Fory
public Fory Register<T, TSerializer>(uint typeId)
where TSerializer : Serializer<T>, new()
{
- Serializer serializer = _typeResolver.RegisterSerializer<T,
TSerializer>();
- _typeResolver.Register(typeof(T), typeId, serializer);
+ TypeInfo typeInfo = _typeResolver.RegisterSerializer<T, TSerializer>();
+ _typeResolver.Register(typeof(T), typeId, typeInfo);
return this;
}
public Fory Register<T, TSerializer>(string typeNamespace, string typeName)
where TSerializer : Serializer<T>, new()
{
- Serializer serializer = _typeResolver.RegisterSerializer<T,
TSerializer>();
- _typeResolver.Register(typeof(T), typeNamespace, typeName, serializer);
+ TypeInfo typeInfo = _typeResolver.RegisterSerializer<T, TSerializer>();
+ _typeResolver.Register(typeof(T), typeNamespace, typeName, typeInfo);
return this;
}
@@ -98,7 +98,8 @@ public sealed class Fory
ByteWriter writer = _writeContext.Writer;
writer.Reset();
Serializer<T> serializer = _typeResolver.GetSerializer<T>();
- bool isNone = serializer.IsNone(value);
+ TypeInfo typeInfo = _typeResolver.GetTypeInfo<T>();
+ bool isNone = typeInfo.IsNullableType && value is null;
WriteHead(writer, isNone);
if (!isNone)
{
diff --git a/csharp/src/Fory/NullableKeyDictionary.cs
b/csharp/src/Fory/NullableKeyDictionary.cs
index fc1c0ae6c..544500da8 100644
--- a/csharp/src/Fory/NullableKeyDictionary.cs
+++ b/csharp/src/Fory/NullableKeyDictionary.cs
@@ -390,16 +390,14 @@ public sealed class NullableKeyDictionary<TKey, TValue> :
IDictionary<TKey, TVal
public sealed class NullableKeyDictionarySerializer<TKey, TValue> :
Serializer<NullableKeyDictionary<TKey, TValue>>
{
- public override TypeId StaticTypeId => TypeId.Map;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override NullableKeyDictionary<TKey, TValue> DefaultValue => null!;
- public override bool IsNone(in NullableKeyDictionary<TKey, TValue> value)
=> value is null;
public override void WriteData(WriteContext context, in
NullableKeyDictionary<TKey, TValue> value, bool hasGenerics)
{
Serializer<TKey> keySerializer =
context.TypeResolver.GetSerializer<TKey>();
Serializer<TValue> valueSerializer =
context.TypeResolver.GetSerializer<TValue>();
+ TypeInfo keyTypeInfo = context.TypeResolver.GetTypeInfo<TKey>();
+ TypeInfo valueTypeInfo = context.TypeResolver.GetTypeInfo<TValue>();
NullableKeyDictionary<TKey, TValue> map = value ?? new
NullableKeyDictionary<TKey, TValue>();
context.Writer.WriteVarUInt32((uint)map.Count);
if (map.Count == 0)
@@ -407,12 +405,12 @@ public sealed class NullableKeyDictionarySerializer<TKey,
TValue> : Serializer<N
return;
}
- bool trackKeyRef = context.TrackRef &&
keySerializer.IsReferenceTrackableType;
- bool trackValueRef = context.TrackRef &&
valueSerializer.IsReferenceTrackableType;
- bool keyDeclared = hasGenerics &&
!keySerializer.StaticTypeId.NeedsTypeInfoForField();
- bool valueDeclared = hasGenerics &&
!valueSerializer.StaticTypeId.NeedsTypeInfoForField();
- bool keyDynamicType = keySerializer.StaticTypeId == TypeId.Unknown;
- bool valueDynamicType = valueSerializer.StaticTypeId == TypeId.Unknown;
+ bool trackKeyRef = context.TrackRef &&
keyTypeInfo.IsReferenceTrackableType;
+ bool trackValueRef = context.TrackRef &&
valueTypeInfo.IsReferenceTrackableType;
+ bool keyDeclared = hasGenerics && !keyTypeInfo.NeedsTypeInfoForField();
+ bool valueDeclared = hasGenerics &&
!valueTypeInfo.NeedsTypeInfoForField();
+ bool keyDynamicType = keyTypeInfo.IsDynamicType;
+ bool valueDynamicType = valueTypeInfo.IsDynamicType;
KeyValuePair<TKey, TValue>[] pairs = [.. map];
if (keyDynamicType || valueDynamicType)
{
@@ -426,6 +424,8 @@ public sealed class NullableKeyDictionarySerializer<TKey,
TValue> : Serializer<N
valueDeclared,
keyDynamicType,
valueDynamicType,
+ keyTypeInfo,
+ valueTypeInfo,
keySerializer,
valueSerializer);
return;
@@ -433,8 +433,8 @@ public sealed class NullableKeyDictionarySerializer<TKey,
TValue> : Serializer<N
foreach (KeyValuePair<TKey, TValue> entry in pairs)
{
- bool keyIsNull = entry.Key is null ||
keySerializer.IsNoneObject(entry.Key);
- bool valueIsNull = valueSerializer.IsNoneObject(entry.Value);
+ bool keyIsNull = context.TypeResolver.IsNoneObject(keyTypeInfo,
entry.Key);
+ bool valueIsNull =
context.TypeResolver.IsNoneObject(valueTypeInfo, entry.Value);
byte header = 0;
if (trackKeyRef)
{
@@ -474,7 +474,7 @@ public sealed class NullableKeyDictionarySerializer<TKey,
TValue> : Serializer<N
{
if (!valueDeclared)
{
- valueSerializer.WriteTypeInfo(context);
+ context.TypeResolver.WriteTypeInfo(valueSerializer,
context);
}
valueSerializer.Write(
@@ -490,7 +490,7 @@ public sealed class NullableKeyDictionarySerializer<TKey,
TValue> : Serializer<N
{
if (!keyDeclared)
{
- keySerializer.WriteTypeInfo(context);
+ context.TypeResolver.WriteTypeInfo(keySerializer, context);
}
keySerializer.Write(
@@ -505,12 +505,12 @@ public sealed class NullableKeyDictionarySerializer<TKey,
TValue> : Serializer<N
context.Writer.WriteUInt8(1);
if (!keyDeclared)
{
- keySerializer.WriteTypeInfo(context);
+ context.TypeResolver.WriteTypeInfo(keySerializer, context);
}
if (!valueDeclared)
{
- valueSerializer.WriteTypeInfo(context);
+ context.TypeResolver.WriteTypeInfo(valueSerializer, context);
}
keySerializer.Write(
@@ -532,6 +532,8 @@ public sealed class NullableKeyDictionarySerializer<TKey,
TValue> : Serializer<N
{
Serializer<TKey> keySerializer =
context.TypeResolver.GetSerializer<TKey>();
Serializer<TValue> valueSerializer =
context.TypeResolver.GetSerializer<TValue>();
+ TypeInfo keyTypeInfo = context.TypeResolver.GetTypeInfo<TKey>();
+ TypeInfo valueTypeInfo = context.TypeResolver.GetTypeInfo<TValue>();
int totalLength = checked((int)context.Reader.ReadVarUInt32());
if (totalLength == 0)
{
@@ -539,9 +541,9 @@ public sealed class NullableKeyDictionarySerializer<TKey,
TValue> : Serializer<N
}
NullableKeyDictionary<TKey, TValue> map = new();
- bool keyDynamicType = keySerializer.StaticTypeId == TypeId.Unknown;
- bool valueDynamicType = valueSerializer.StaticTypeId == TypeId.Unknown;
- bool canonicalizeValues = context.TrackRef &&
valueSerializer.IsReferenceTrackableType;
+ bool keyDynamicType = keyTypeInfo.IsDynamicType;
+ bool valueDynamicType = valueTypeInfo.IsDynamicType;
+ bool canonicalizeValues = context.TrackRef &&
valueTypeInfo.IsReferenceTrackableType;
int readCount = 0;
while (readCount < totalLength)
@@ -603,7 +605,7 @@ public sealed class NullableKeyDictionarySerializer<TKey,
TValue> : Serializer<N
}
else
{
- keySerializer.ReadTypeInfo(context);
+ context.TypeResolver.ReadTypeInfo(keySerializer,
context);
}
}
@@ -615,7 +617,7 @@ public sealed class NullableKeyDictionarySerializer<TKey,
TValue> : Serializer<N
}
else
{
- valueSerializer.ReadTypeInfo(context);
+ context.TypeResolver.ReadTypeInfo(valueSerializer,
context);
}
}
@@ -655,12 +657,12 @@ public sealed class NullableKeyDictionarySerializer<TKey,
TValue> : Serializer<N
if (!keyDeclared)
{
- keySerializer.ReadTypeInfo(context);
+ context.TypeResolver.ReadTypeInfo(keySerializer, context);
}
if (!valueDeclared)
{
- valueSerializer.ReadTypeInfo(context);
+ context.TypeResolver.ReadTypeInfo(valueSerializer, context);
}
for (int i = 0; i < chunkSize; i++)
@@ -696,13 +698,15 @@ public sealed class NullableKeyDictionarySerializer<TKey,
TValue> : Serializer<N
bool valueDeclared,
bool keyDynamicType,
bool valueDynamicType,
+ TypeInfo keyTypeInfo,
+ TypeInfo valueTypeInfo,
Serializer<TKey> keySerializer,
Serializer<TValue> valueSerializer)
{
foreach (KeyValuePair<TKey, TValue> pair in pairs)
{
- bool keyIsNull = pair.Key is null ||
keySerializer.IsNoneObject(pair.Key);
- bool valueIsNull = valueSerializer.IsNoneObject(pair.Value);
+ bool keyIsNull = context.TypeResolver.IsNoneObject(keyTypeInfo,
pair.Key);
+ bool valueIsNull =
context.TypeResolver.IsNoneObject(valueTypeInfo, pair.Value);
byte header = 0;
if (trackKeyRef)
{
@@ -769,7 +773,7 @@ public sealed class NullableKeyDictionarySerializer<TKey,
TValue> : Serializer<N
}
else
{
- keySerializer.WriteTypeInfo(context);
+ context.TypeResolver.WriteTypeInfo(keySerializer, context);
}
}
@@ -781,7 +785,7 @@ public sealed class NullableKeyDictionarySerializer<TKey,
TValue> : Serializer<N
}
else
{
- valueSerializer.WriteTypeInfo(context);
+ context.TypeResolver.WriteTypeInfo(valueSerializer,
context);
}
}
diff --git a/csharp/src/Fory/OptionalSerializer.cs
b/csharp/src/Fory/OptionalSerializer.cs
index 0f638bdb3..9cb42c7eb 100644
--- a/csharp/src/Fory/OptionalSerializer.cs
+++ b/csharp/src/Fory/OptionalSerializer.cs
@@ -19,21 +19,8 @@ namespace Apache.Fory;
public sealed class NullableSerializer<T> : Serializer<T?> where T : struct
{
- private readonly Serializer<T> _defaultWrappedSerializer = new
TypeResolver().GetSerializer<T>();
-
- public override TypeId StaticTypeId =>
_defaultWrappedSerializer.StaticTypeId;
-
- public override bool IsNullableType => true;
-
- public override bool IsReferenceTrackableType =>
_defaultWrappedSerializer.IsReferenceTrackableType;
-
public override T? DefaultValue => null;
- public override bool IsNone(in T? value)
- {
- return !value.HasValue;
- }
-
public override void WriteData(WriteContext context, in T? value, bool
hasGenerics)
{
if (!value.HasValue)
@@ -52,23 +39,6 @@ public sealed class NullableSerializer<T> : Serializer<T?>
where T : struct
return wrappedSerializer.ReadData(context);
}
- public override void WriteTypeInfo(WriteContext context)
- {
- Serializer<T> wrappedSerializer =
context.TypeResolver.GetSerializer<T>();
- wrappedSerializer.WriteTypeInfo(context);
- }
-
- public override void ReadTypeInfo(ReadContext context)
- {
- Serializer<T> wrappedSerializer =
context.TypeResolver.GetSerializer<T>();
- wrappedSerializer.ReadTypeInfo(context);
- }
-
- public override IReadOnlyList<TypeMetaFieldInfo>
CompatibleTypeMetaFields(bool trackRef)
- {
- return _defaultWrappedSerializer.CompatibleTypeMetaFields(trackRef);
- }
-
public override void Write(WriteContext context, in T? value, RefMode
refMode, bool writeTypeInfo, bool hasGenerics)
{
Serializer<T> wrappedSerializer =
context.TypeResolver.GetSerializer<T>();
diff --git a/csharp/src/Fory/PrimitiveArraySerializers.cs
b/csharp/src/Fory/PrimitiveArraySerializers.cs
index e2882c8e0..505ec0dab 100644
--- a/csharp/src/Fory/PrimitiveArraySerializers.cs
+++ b/csharp/src/Fory/PrimitiveArraySerializers.cs
@@ -19,16 +19,11 @@ namespace Apache.Fory;
internal sealed class BoolArraySerializer : Serializer<bool[]>
{
- public override TypeId StaticTypeId => TypeId.BoolArray;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override bool[] DefaultValue => null!;
- public override bool IsNone(in bool[] value) => value is null;
-
public override void WriteData(WriteContext context, in bool[] value, bool
hasGenerics)
{
_ = hasGenerics;
@@ -55,16 +50,11 @@ internal sealed class BoolArraySerializer :
Serializer<bool[]>
internal sealed class Int8ArraySerializer : Serializer<sbyte[]>
{
- public override TypeId StaticTypeId => TypeId.Int8Array;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override sbyte[] DefaultValue => null!;
- public override bool IsNone(in sbyte[] value) => value is null;
-
public override void WriteData(WriteContext context, in sbyte[] value,
bool hasGenerics)
{
_ = hasGenerics;
@@ -91,16 +81,11 @@ internal sealed class Int8ArraySerializer :
Serializer<sbyte[]>
internal sealed class Int16ArraySerializer : Serializer<short[]>
{
- public override TypeId StaticTypeId => TypeId.Int16Array;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override short[] DefaultValue => null!;
- public override bool IsNone(in short[] value) => value is null;
-
public override void WriteData(WriteContext context, in short[] value,
bool hasGenerics)
{
_ = hasGenerics;
@@ -132,16 +117,11 @@ internal sealed class Int16ArraySerializer :
Serializer<short[]>
internal sealed class Int32ArraySerializer : Serializer<int[]>
{
- public override TypeId StaticTypeId => TypeId.Int32Array;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override int[] DefaultValue => null!;
- public override bool IsNone(in int[] value) => value is null;
-
public override void WriteData(WriteContext context, in int[] value, bool
hasGenerics)
{
_ = hasGenerics;
@@ -173,16 +153,11 @@ internal sealed class Int32ArraySerializer :
Serializer<int[]>
internal sealed class Int64ArraySerializer : Serializer<long[]>
{
- public override TypeId StaticTypeId => TypeId.Int64Array;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override long[] DefaultValue => null!;
- public override bool IsNone(in long[] value) => value is null;
-
public override void WriteData(WriteContext context, in long[] value, bool
hasGenerics)
{
_ = hasGenerics;
@@ -214,16 +189,11 @@ internal sealed class Int64ArraySerializer :
Serializer<long[]>
internal sealed class UInt16ArraySerializer : Serializer<ushort[]>
{
- public override TypeId StaticTypeId => TypeId.UInt16Array;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override ushort[] DefaultValue => null!;
- public override bool IsNone(in ushort[] value) => value is null;
-
public override void WriteData(WriteContext context, in ushort[] value,
bool hasGenerics)
{
_ = hasGenerics;
@@ -255,16 +225,11 @@ internal sealed class UInt16ArraySerializer :
Serializer<ushort[]>
internal sealed class UInt32ArraySerializer : Serializer<uint[]>
{
- public override TypeId StaticTypeId => TypeId.UInt32Array;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override uint[] DefaultValue => null!;
- public override bool IsNone(in uint[] value) => value is null;
-
public override void WriteData(WriteContext context, in uint[] value, bool
hasGenerics)
{
_ = hasGenerics;
@@ -296,16 +261,11 @@ internal sealed class UInt32ArraySerializer :
Serializer<uint[]>
internal sealed class UInt64ArraySerializer : Serializer<ulong[]>
{
- public override TypeId StaticTypeId => TypeId.UInt64Array;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override ulong[] DefaultValue => null!;
- public override bool IsNone(in ulong[] value) => value is null;
-
public override void WriteData(WriteContext context, in ulong[] value,
bool hasGenerics)
{
_ = hasGenerics;
@@ -337,16 +297,11 @@ internal sealed class UInt64ArraySerializer :
Serializer<ulong[]>
internal sealed class Float32ArraySerializer : Serializer<float[]>
{
- public override TypeId StaticTypeId => TypeId.Float32Array;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override float[] DefaultValue => null!;
- public override bool IsNone(in float[] value) => value is null;
-
public override void WriteData(WriteContext context, in float[] value,
bool hasGenerics)
{
_ = hasGenerics;
@@ -378,16 +333,11 @@ internal sealed class Float32ArraySerializer :
Serializer<float[]>
internal sealed class Float64ArraySerializer : Serializer<double[]>
{
- public override TypeId StaticTypeId => TypeId.Float64Array;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override double[] DefaultValue => null!;
- public override bool IsNone(in double[] value) => value is null;
-
public override void WriteData(WriteContext context, in double[] value,
bool hasGenerics)
{
_ = hasGenerics;
diff --git a/csharp/src/Fory/PrimitiveCollectionSerializers.cs
b/csharp/src/Fory/PrimitiveCollectionSerializers.cs
index 17850477a..e029816fb 100644
--- a/csharp/src/Fory/PrimitiveCollectionSerializers.cs
+++ b/csharp/src/Fory/PrimitiveCollectionSerializers.cs
@@ -53,16 +53,11 @@ internal sealed class ListBoolSerializer :
Serializer<List<bool>>
{
private static readonly ListSerializer<bool> Fallback = new();
- public override TypeId StaticTypeId => TypeId.List;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override List<bool> DefaultValue => null!;
- public override bool IsNone(in List<bool> value) => value is null;
-
public override void WriteData(WriteContext context, in List<bool> value,
bool hasGenerics)
{
List<bool> list = value ?? [];
@@ -83,16 +78,11 @@ internal sealed class ListInt8Serializer :
Serializer<List<sbyte>>
{
private static readonly ListSerializer<sbyte> Fallback = new();
- public override TypeId StaticTypeId => TypeId.List;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override List<sbyte> DefaultValue => null!;
- public override bool IsNone(in List<sbyte> value) => value is null;
-
public override void WriteData(WriteContext context, in List<sbyte> value,
bool hasGenerics)
{
List<sbyte> list = value ?? [];
@@ -113,16 +103,11 @@ internal sealed class ListInt16Serializer :
Serializer<List<short>>
{
private static readonly ListSerializer<short> Fallback = new();
- public override TypeId StaticTypeId => TypeId.List;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override List<short> DefaultValue => null!;
- public override bool IsNone(in List<short> value) => value is null;
-
public override void WriteData(WriteContext context, in List<short> value,
bool hasGenerics)
{
List<short> list = value ?? [];
@@ -143,16 +128,11 @@ internal sealed class ListIntSerializer :
Serializer<List<int>>
{
private static readonly ListSerializer<int> Fallback = new();
- public override TypeId StaticTypeId => TypeId.List;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override List<int> DefaultValue => null!;
- public override bool IsNone(in List<int> value) => value is null;
-
public override void WriteData(WriteContext context, in List<int> value,
bool hasGenerics)
{
List<int> list = value ?? [];
@@ -173,16 +153,11 @@ internal sealed class ListLongSerializer :
Serializer<List<long>>
{
private static readonly ListSerializer<long> Fallback = new();
- public override TypeId StaticTypeId => TypeId.List;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override List<long> DefaultValue => null!;
- public override bool IsNone(in List<long> value) => value is null;
-
public override void WriteData(WriteContext context, in List<long> value,
bool hasGenerics)
{
List<long> list = value ?? [];
@@ -203,16 +178,11 @@ internal sealed class ListUInt8Serializer :
Serializer<List<byte>>
{
private static readonly ListSerializer<byte> Fallback = new();
- public override TypeId StaticTypeId => TypeId.List;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override List<byte> DefaultValue => null!;
- public override bool IsNone(in List<byte> value) => value is null;
-
public override void WriteData(WriteContext context, in List<byte> value,
bool hasGenerics)
{
List<byte> list = value ?? [];
@@ -233,16 +203,11 @@ internal sealed class ListUInt16Serializer :
Serializer<List<ushort>>
{
private static readonly ListSerializer<ushort> Fallback = new();
- public override TypeId StaticTypeId => TypeId.List;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override List<ushort> DefaultValue => null!;
- public override bool IsNone(in List<ushort> value) => value is null;
-
public override void WriteData(WriteContext context, in List<ushort>
value, bool hasGenerics)
{
List<ushort> list = value ?? [];
@@ -263,16 +228,11 @@ internal sealed class ListUIntSerializer :
Serializer<List<uint>>
{
private static readonly ListSerializer<uint> Fallback = new();
- public override TypeId StaticTypeId => TypeId.List;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override List<uint> DefaultValue => null!;
- public override bool IsNone(in List<uint> value) => value is null;
-
public override void WriteData(WriteContext context, in List<uint> value,
bool hasGenerics)
{
List<uint> list = value ?? [];
@@ -293,16 +253,11 @@ internal sealed class ListULongSerializer :
Serializer<List<ulong>>
{
private static readonly ListSerializer<ulong> Fallback = new();
- public override TypeId StaticTypeId => TypeId.List;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override List<ulong> DefaultValue => null!;
- public override bool IsNone(in List<ulong> value) => value is null;
-
public override void WriteData(WriteContext context, in List<ulong> value,
bool hasGenerics)
{
List<ulong> list = value ?? [];
@@ -323,16 +278,11 @@ internal sealed class ListFloatSerializer :
Serializer<List<float>>
{
private static readonly ListSerializer<float> Fallback = new();
- public override TypeId StaticTypeId => TypeId.List;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override List<float> DefaultValue => null!;
- public override bool IsNone(in List<float> value) => value is null;
-
public override void WriteData(WriteContext context, in List<float> value,
bool hasGenerics)
{
List<float> list = value ?? [];
@@ -353,16 +303,11 @@ internal sealed class ListDoubleSerializer :
Serializer<List<double>>
{
private static readonly ListSerializer<double> Fallback = new();
- public override TypeId StaticTypeId => TypeId.List;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override List<double> DefaultValue => null!;
- public override bool IsNone(in List<double> value) => value is null;
-
public override void WriteData(WriteContext context, in List<double>
value, bool hasGenerics)
{
List<double> list = value ?? [];
@@ -383,16 +328,11 @@ internal sealed class ListStringSerializer :
Serializer<List<string>>
{
private static readonly ListSerializer<string> Fallback = new();
- public override TypeId StaticTypeId => TypeId.List;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override List<string> DefaultValue => null!;
- public override bool IsNone(in List<string> value) => value is null;
-
public override void WriteData(WriteContext context, in List<string>
value, bool hasGenerics)
{
List<string> list = value ?? [];
@@ -441,16 +381,11 @@ internal sealed class SetInt8Serializer :
Serializer<HashSet<sbyte>>
{
private static readonly SetSerializer<sbyte> Fallback = new();
- public override TypeId StaticTypeId => TypeId.Set;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override HashSet<sbyte> DefaultValue => null!;
- public override bool IsNone(in HashSet<sbyte> value) => value is null;
-
public override void WriteData(WriteContext context, in HashSet<sbyte>
value, bool hasGenerics)
{
HashSet<sbyte> set = value ?? [];
@@ -471,16 +406,11 @@ internal sealed class SetInt16Serializer :
Serializer<HashSet<short>>
{
private static readonly SetSerializer<short> Fallback = new();
- public override TypeId StaticTypeId => TypeId.Set;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override HashSet<short> DefaultValue => null!;
- public override bool IsNone(in HashSet<short> value) => value is null;
-
public override void WriteData(WriteContext context, in HashSet<short>
value, bool hasGenerics)
{
HashSet<short> set = value ?? [];
@@ -501,16 +431,11 @@ internal sealed class SetIntSerializer :
Serializer<HashSet<int>>
{
private static readonly SetSerializer<int> Fallback = new();
- public override TypeId StaticTypeId => TypeId.Set;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override HashSet<int> DefaultValue => null!;
- public override bool IsNone(in HashSet<int> value) => value is null;
-
public override void WriteData(WriteContext context, in HashSet<int>
value, bool hasGenerics)
{
HashSet<int> set = value ?? [];
@@ -531,16 +456,11 @@ internal sealed class SetLongSerializer :
Serializer<HashSet<long>>
{
private static readonly SetSerializer<long> Fallback = new();
- public override TypeId StaticTypeId => TypeId.Set;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override HashSet<long> DefaultValue => null!;
- public override bool IsNone(in HashSet<long> value) => value is null;
-
public override void WriteData(WriteContext context, in HashSet<long>
value, bool hasGenerics)
{
HashSet<long> set = value ?? [];
@@ -561,16 +481,11 @@ internal sealed class SetUInt8Serializer :
Serializer<HashSet<byte>>
{
private static readonly SetSerializer<byte> Fallback = new();
- public override TypeId StaticTypeId => TypeId.Set;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override HashSet<byte> DefaultValue => null!;
- public override bool IsNone(in HashSet<byte> value) => value is null;
-
public override void WriteData(WriteContext context, in HashSet<byte>
value, bool hasGenerics)
{
HashSet<byte> set = value ?? [];
@@ -591,16 +506,11 @@ internal sealed class SetUInt16Serializer :
Serializer<HashSet<ushort>>
{
private static readonly SetSerializer<ushort> Fallback = new();
- public override TypeId StaticTypeId => TypeId.Set;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override HashSet<ushort> DefaultValue => null!;
- public override bool IsNone(in HashSet<ushort> value) => value is null;
-
public override void WriteData(WriteContext context, in HashSet<ushort>
value, bool hasGenerics)
{
HashSet<ushort> set = value ?? [];
@@ -621,16 +531,11 @@ internal sealed class SetUIntSerializer :
Serializer<HashSet<uint>>
{
private static readonly SetSerializer<uint> Fallback = new();
- public override TypeId StaticTypeId => TypeId.Set;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override HashSet<uint> DefaultValue => null!;
- public override bool IsNone(in HashSet<uint> value) => value is null;
-
public override void WriteData(WriteContext context, in HashSet<uint>
value, bool hasGenerics)
{
HashSet<uint> set = value ?? [];
@@ -651,16 +556,11 @@ internal sealed class SetULongSerializer :
Serializer<HashSet<ulong>>
{
private static readonly SetSerializer<ulong> Fallback = new();
- public override TypeId StaticTypeId => TypeId.Set;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override HashSet<ulong> DefaultValue => null!;
- public override bool IsNone(in HashSet<ulong> value) => value is null;
-
public override void WriteData(WriteContext context, in HashSet<ulong>
value, bool hasGenerics)
{
HashSet<ulong> set = value ?? [];
@@ -681,16 +581,11 @@ internal sealed class SetFloatSerializer :
Serializer<HashSet<float>>
{
private static readonly SetSerializer<float> Fallback = new();
- public override TypeId StaticTypeId => TypeId.Set;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override HashSet<float> DefaultValue => null!;
- public override bool IsNone(in HashSet<float> value) => value is null;
-
public override void WriteData(WriteContext context, in HashSet<float>
value, bool hasGenerics)
{
HashSet<float> set = value ?? [];
@@ -711,16 +606,11 @@ internal sealed class SetDoubleSerializer :
Serializer<HashSet<double>>
{
private static readonly SetSerializer<double> Fallback = new();
- public override TypeId StaticTypeId => TypeId.Set;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override HashSet<double> DefaultValue => null!;
- public override bool IsNone(in HashSet<double> value) => value is null;
-
public override void WriteData(WriteContext context, in HashSet<double>
value, bool hasGenerics)
{
HashSet<double> set = value ?? [];
@@ -742,16 +632,11 @@ internal class PrimitiveLinkedListSerializer<T, TCodec> :
Serializer<LinkedList<
{
private static readonly LinkedListSerializer<T> Fallback = new();
- public override TypeId StaticTypeId => TypeId.List;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override LinkedList<T> DefaultValue => null!;
- public override bool IsNone(in LinkedList<T> value) => value is null;
-
public override void WriteData(WriteContext context, in LinkedList<T>
value, bool hasGenerics)
{
if (TCodec.IsNullable)
@@ -778,16 +663,11 @@ internal class PrimitiveQueueSerializer<T, TCodec> :
Serializer<Queue<T>>
{
private static readonly QueueSerializer<T> Fallback = new();
- public override TypeId StaticTypeId => TypeId.List;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override Queue<T> DefaultValue => null!;
- public override bool IsNone(in Queue<T> value) => value is null;
-
public override void WriteData(WriteContext context, in Queue<T> value,
bool hasGenerics)
{
if (TCodec.IsNullable)
@@ -814,16 +694,11 @@ internal class PrimitiveStackSerializer<T, TCodec> :
Serializer<Stack<T>>
{
private static readonly StackSerializer<T> Fallback = new();
- public override TypeId StaticTypeId => TypeId.List;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override Stack<T> DefaultValue => null!;
- public override bool IsNone(in Stack<T> value) => value is null;
-
public override void WriteData(WriteContext context, in Stack<T> value,
bool hasGenerics)
{
if (TCodec.IsNullable)
@@ -857,16 +732,11 @@ internal class PrimitiveSortedSetSerializer<T, TCodec> :
Serializer<SortedSet<T>
{
private static readonly SortedSetSerializer<T> Fallback = new();
- public override TypeId StaticTypeId => TypeId.Set;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override SortedSet<T> DefaultValue => null!;
- public override bool IsNone(in SortedSet<T> value) => value is null;
-
public override void WriteData(WriteContext context, in SortedSet<T>
value, bool hasGenerics)
{
if (TCodec.IsNullable)
@@ -894,16 +764,11 @@ internal class PrimitiveImmutableHashSetSerializer<T,
TCodec> : Serializer<Immut
{
private static readonly ImmutableHashSetSerializer<T> Fallback = new();
- public override TypeId StaticTypeId => TypeId.Set;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override ImmutableHashSet<T> DefaultValue => null!;
- public override bool IsNone(in ImmutableHashSet<T> value) => value is null;
-
public override void WriteData(WriteContext context, in
ImmutableHashSet<T> value, bool hasGenerics)
{
if (TCodec.IsNullable)
diff --git a/csharp/src/Fory/PrimitiveDictionarySerializers.cs
b/csharp/src/Fory/PrimitiveDictionarySerializers.cs
index cfc1a1913..3e024b92e 100644
--- a/csharp/src/Fory/PrimitiveDictionarySerializers.cs
+++ b/csharp/src/Fory/PrimitiveDictionarySerializers.cs
@@ -732,16 +732,11 @@ internal class PrimitiveDictionarySerializer<TKey,
TValue, TKeyCodec, TValueCode
where TKeyCodec : struct, IPrimitiveDictionaryCodec<TKey>
where TValueCodec : struct, IPrimitiveDictionaryCodec<TValue>
{
- public override TypeId StaticTypeId => TypeId.Map;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override Dictionary<TKey, TValue> DefaultValue => null!;
- public override bool IsNone(in Dictionary<TKey, TValue> value) => value is
null;
-
public override void WriteData(WriteContext context, in Dictionary<TKey,
TValue> value, bool hasGenerics)
{
Dictionary<TKey, TValue> map = value ?? [];
@@ -785,16 +780,11 @@ internal class PrimitiveSortedDictionarySerializer<TKey,
TValue, TKeyCodec, TVal
where TKeyCodec : struct, IPrimitiveDictionaryCodec<TKey>
where TValueCodec : struct, IPrimitiveDictionaryCodec<TValue>
{
- public override TypeId StaticTypeId => TypeId.Map;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override SortedDictionary<TKey, TValue> DefaultValue => null!;
- public override bool IsNone(in SortedDictionary<TKey, TValue> value) =>
value is null;
-
public override void WriteData(WriteContext context, in
SortedDictionary<TKey, TValue> value, bool hasGenerics)
{
SortedDictionary<TKey, TValue> map = value ?? new
SortedDictionary<TKey, TValue>();
@@ -838,16 +828,11 @@ internal class PrimitiveSortedListSerializer<TKey,
TValue, TKeyCodec, TValueCode
where TKeyCodec : struct, IPrimitiveDictionaryCodec<TKey>
where TValueCodec : struct, IPrimitiveDictionaryCodec<TValue>
{
- public override TypeId StaticTypeId => TypeId.Map;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override SortedList<TKey, TValue> DefaultValue => null!;
- public override bool IsNone(in SortedList<TKey, TValue> value) => value is
null;
-
public override void WriteData(WriteContext context, in SortedList<TKey,
TValue> value, bool hasGenerics)
{
SortedList<TKey, TValue> map = value ?? new SortedList<TKey, TValue>();
@@ -891,16 +876,11 @@ internal class
PrimitiveConcurrentDictionarySerializer<TKey, TValue, TKeyCodec,
where TKeyCodec : struct, IPrimitiveDictionaryCodec<TKey>
where TValueCodec : struct, IPrimitiveDictionaryCodec<TValue>
{
- public override TypeId StaticTypeId => TypeId.Map;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override ConcurrentDictionary<TKey, TValue> DefaultValue => null!;
- public override bool IsNone(in ConcurrentDictionary<TKey, TValue> value)
=> value is null;
-
public override void WriteData(WriteContext context, in
ConcurrentDictionary<TKey, TValue> value, bool hasGenerics)
{
ConcurrentDictionary<TKey, TValue> map = value ?? new
ConcurrentDictionary<TKey, TValue>();
diff --git a/csharp/src/Fory/PrimitiveSerializers.cs
b/csharp/src/Fory/PrimitiveSerializers.cs
index 98d85dcca..ad5e3e959 100644
--- a/csharp/src/Fory/PrimitiveSerializers.cs
+++ b/csharp/src/Fory/PrimitiveSerializers.cs
@@ -26,7 +26,6 @@ internal enum ForyStringEncoding : ulong
public sealed class BoolSerializer : Serializer<bool>
{
- public override TypeId StaticTypeId => TypeId.Bool;
public override bool DefaultValue => false;
@@ -44,7 +43,6 @@ public sealed class BoolSerializer : Serializer<bool>
public sealed class Int8Serializer : Serializer<sbyte>
{
- public override TypeId StaticTypeId => TypeId.Int8;
public override sbyte DefaultValue => 0;
@@ -62,7 +60,6 @@ public sealed class Int8Serializer : Serializer<sbyte>
public sealed class Int16Serializer : Serializer<short>
{
- public override TypeId StaticTypeId => TypeId.Int16;
public override short DefaultValue => 0;
@@ -80,7 +77,6 @@ public sealed class Int16Serializer : Serializer<short>
public sealed class Int32Serializer : Serializer<int>
{
- public override TypeId StaticTypeId => TypeId.VarInt32;
public override int DefaultValue => 0;
@@ -98,7 +94,6 @@ public sealed class Int32Serializer : Serializer<int>
public sealed class Int64Serializer : Serializer<long>
{
- public override TypeId StaticTypeId => TypeId.VarInt64;
public override long DefaultValue => 0;
@@ -116,7 +111,6 @@ public sealed class Int64Serializer : Serializer<long>
public sealed class UInt8Serializer : Serializer<byte>
{
- public override TypeId StaticTypeId => TypeId.UInt8;
public override byte DefaultValue => 0;
@@ -134,7 +128,6 @@ public sealed class UInt8Serializer : Serializer<byte>
public sealed class UInt16Serializer : Serializer<ushort>
{
- public override TypeId StaticTypeId => TypeId.UInt16;
public override ushort DefaultValue => 0;
@@ -152,7 +145,6 @@ public sealed class UInt16Serializer : Serializer<ushort>
public sealed class UInt32Serializer : Serializer<uint>
{
- public override TypeId StaticTypeId => TypeId.VarUInt32;
public override uint DefaultValue => 0;
@@ -170,7 +162,6 @@ public sealed class UInt32Serializer : Serializer<uint>
public sealed class UInt64Serializer : Serializer<ulong>
{
- public override TypeId StaticTypeId => TypeId.VarUInt64;
public override ulong DefaultValue => 0;
@@ -188,7 +179,6 @@ public sealed class UInt64Serializer : Serializer<ulong>
public sealed class Float32Serializer : Serializer<float>
{
- public override TypeId StaticTypeId => TypeId.Float32;
public override float DefaultValue => 0;
@@ -206,7 +196,6 @@ public sealed class Float32Serializer : Serializer<float>
public sealed class Float64Serializer : Serializer<double>
{
- public override TypeId StaticTypeId => TypeId.Float64;
public override double DefaultValue => 0;
@@ -224,14 +213,10 @@ public sealed class Float64Serializer : Serializer<double>
public sealed class BinarySerializer : Serializer<byte[]>
{
- public override TypeId StaticTypeId => TypeId.Binary;
- public override bool IsNullableType => true;
public override byte[] DefaultValue => null!;
- public override bool IsNone(in byte[] value) => value is null;
-
public override void WriteData(WriteContext context, in byte[] value, bool
hasGenerics)
{
_ = hasGenerics;
diff --git a/csharp/src/Fory/Serializer.cs b/csharp/src/Fory/Serializer.cs
index 009014cfb..a90242a3e 100644
--- a/csharp/src/Fory/Serializer.cs
+++ b/csharp/src/Fory/Serializer.cs
@@ -17,56 +17,11 @@
namespace Apache.Fory;
-public abstract class Serializer
+public abstract class Serializer<T>
{
- public abstract Type Type { get; }
-
- public abstract TypeId StaticTypeId { get; }
-
- public abstract bool IsNullableType { get; }
-
- public abstract bool IsReferenceTrackableType { get; }
-
- public abstract object? DefaultObject { get; }
-
- public abstract bool IsNoneObject(object? value);
-
- public abstract void WriteDataObject(WriteContext context, object? value,
bool hasGenerics);
-
- public abstract object? ReadDataObject(ReadContext context);
-
- public abstract void WriteObject(WriteContext context, object? value,
RefMode refMode, bool writeTypeInfo, bool hasGenerics);
-
- public abstract object? ReadObject(ReadContext context, RefMode refMode,
bool readTypeInfo);
-
- public abstract void WriteTypeInfo(WriteContext context);
-
- public abstract void ReadTypeInfo(ReadContext context);
-
- public abstract IReadOnlyList<TypeMetaFieldInfo>
CompatibleTypeMetaFields(bool trackRef);
-
- public abstract Serializer<T> RequireSerializer<T>();
-}
-
-public abstract class Serializer<T> : Serializer
-{
- public override Type Type => typeof(T);
-
- public abstract override TypeId StaticTypeId { get; }
-
- public override bool IsNullableType => false;
-
- public override bool IsReferenceTrackableType => false;
-
public virtual T DefaultValue => default!;
- public override object? DefaultObject => DefaultValue;
-
- public virtual bool IsNone(in T value)
- {
- _ = value;
- return false;
- }
+ internal object? DefaultObject => DefaultValue;
public abstract void WriteData(WriteContext context, in T value, bool
hasGenerics);
@@ -78,7 +33,6 @@ public abstract class Serializer<T> : Serializer
{
bool wroteTrackingRefFlag = false;
if (refMode == RefMode.Tracking &&
- IsReferenceTrackableType &&
value is object obj)
{
if (context.RefWriter.TryWriteReference(context.Writer, obj))
@@ -91,7 +45,7 @@ public abstract class Serializer<T> : Serializer
if (!wroteTrackingRefFlag)
{
- if (IsNullableType && IsNone(value))
+ if (value is null)
{
context.Writer.WriteInt8((sbyte)RefFlag.Null);
return;
@@ -103,7 +57,7 @@ public abstract class Serializer<T> : Serializer
if (writeTypeInfo)
{
- WriteTypeInfo(context);
+ context.TypeResolver.WriteTypeInfo(this, context);
}
WriteData(context, value, hasGenerics);
@@ -130,7 +84,7 @@ public abstract class Serializer<T> : Serializer
context.RefReader.PushPendingReference(reservedRefId);
if (readTypeInfo)
{
- ReadTypeInfo(context);
+ context.TypeResolver.ReadTypeInfo(this, context);
}
T value = ReadData(context);
@@ -147,81 +101,9 @@ public abstract class Serializer<T> : Serializer
if (readTypeInfo)
{
- ReadTypeInfo(context);
- }
-
- return ReadData(context);
- }
-
- public override void WriteTypeInfo(WriteContext context)
- {
- context.TypeResolver.WriteTypeInfo(Type, this, context);
- }
-
- public override void ReadTypeInfo(ReadContext context)
- {
- context.TypeResolver.ReadTypeInfo(Type, this, context);
- }
-
- public override IReadOnlyList<TypeMetaFieldInfo>
CompatibleTypeMetaFields(bool trackRef)
- {
- _ = trackRef;
- return [];
- }
-
- public override bool IsNoneObject(object? value)
- {
- if (value is null)
- {
- return IsNullableType;
+ context.TypeResolver.ReadTypeInfo(this, context);
}
- return value is T typed && IsNone(typed);
- }
-
- public override void WriteDataObject(WriteContext context, object? value,
bool hasGenerics)
- {
- WriteData(context, CoerceValue(value), hasGenerics);
- }
-
- public override object? ReadDataObject(ReadContext context)
- {
return ReadData(context);
}
-
- public override void WriteObject(WriteContext context, object? value,
RefMode refMode, bool writeTypeInfo, bool hasGenerics)
- {
- Write(context, CoerceValue(value), refMode, writeTypeInfo,
hasGenerics);
- }
-
- public override object? ReadObject(ReadContext context, RefMode refMode,
bool readTypeInfo)
- {
- return Read(context, refMode, readTypeInfo);
- }
-
- public override Serializer<TCast> RequireSerializer<TCast>()
- {
- if (typeof(TCast) == typeof(T))
- {
- return (Serializer<TCast>)(object)this;
- }
-
- throw new InvalidDataException($"serializer type mismatch for
{typeof(TCast)}");
- }
-
- protected virtual T CoerceValue(object? value)
- {
- if (value is T typed)
- {
- return typed;
- }
-
- if (value is null && IsNullableType)
- {
- return DefaultValue;
- }
-
- throw new InvalidDataException(
- $"serializer {GetType().Name} expected value of type {typeof(T)},
got {value?.GetType()}");
- }
}
diff --git a/csharp/src/Fory/StringSerializer.cs
b/csharp/src/Fory/StringSerializer.cs
index 9dcf4ff5a..1e56fcfd6 100644
--- a/csharp/src/Fory/StringSerializer.cs
+++ b/csharp/src/Fory/StringSerializer.cs
@@ -21,14 +21,10 @@ namespace Apache.Fory;
public sealed class StringSerializer : Serializer<string>
{
- public override TypeId StaticTypeId => TypeId.String;
- public override bool IsNullableType => true;
public override string DefaultValue => null!;
- public override bool IsNone(in string value) => value is null;
-
public override void WriteData(WriteContext context, in string value, bool
hasGenerics)
{
_ = hasGenerics;
diff --git a/csharp/src/Fory/TimeSerializers.cs
b/csharp/src/Fory/TimeSerializers.cs
index acaf0e99f..24c6825c1 100644
--- a/csharp/src/Fory/TimeSerializers.cs
+++ b/csharp/src/Fory/TimeSerializers.cs
@@ -89,7 +89,6 @@ internal static class TimeCodec
public sealed class DateOnlySerializer : Serializer<DateOnly>
{
- public override TypeId StaticTypeId => TypeId.Date;
public override DateOnly DefaultValue => new(1970, 1, 1);
@@ -107,7 +106,6 @@ public sealed class DateOnlySerializer :
Serializer<DateOnly>
public sealed class DateTimeOffsetSerializer : Serializer<DateTimeOffset>
{
- public override TypeId StaticTypeId => TypeId.Timestamp;
public override DateTimeOffset DefaultValue => DateTimeOffset.UnixEpoch;
@@ -125,7 +123,6 @@ public sealed class DateTimeOffsetSerializer :
Serializer<DateTimeOffset>
public sealed class DateTimeSerializer : Serializer<DateTime>
{
- public override TypeId StaticTypeId => TypeId.Timestamp;
public override DateTime DefaultValue => DateTime.UnixEpoch;
@@ -144,7 +141,6 @@ public sealed class DateTimeSerializer :
Serializer<DateTime>
public sealed class TimeSpanSerializer : Serializer<TimeSpan>
{
- public override TypeId StaticTypeId => TypeId.Duration;
public override TimeSpan DefaultValue => TimeSpan.Zero;
@@ -164,16 +160,11 @@ internal sealed class ListDateOnlySerializer :
Serializer<List<DateOnly>>
{
private static readonly ListSerializer<DateOnly> Fallback = new();
- public override TypeId StaticTypeId => TypeId.List;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override List<DateOnly> DefaultValue => null!;
- public override bool IsNone(in List<DateOnly> value) => value is null;
-
public override void WriteData(WriteContext context, in List<DateOnly>
value, bool hasGenerics)
{
List<DateOnly> list = value ?? [];
@@ -194,16 +185,11 @@ internal sealed class ListDateTimeOffsetSerializer :
Serializer<List<DateTimeOff
{
private static readonly ListSerializer<DateTimeOffset> Fallback = new();
- public override TypeId StaticTypeId => TypeId.List;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override List<DateTimeOffset> DefaultValue => null!;
- public override bool IsNone(in List<DateTimeOffset> value) => value is
null;
-
public override void WriteData(WriteContext context, in
List<DateTimeOffset> value, bool hasGenerics)
{
List<DateTimeOffset> list = value ?? [];
@@ -224,16 +210,11 @@ internal sealed class ListDateTimeSerializer :
Serializer<List<DateTime>>
{
private static readonly ListSerializer<DateTime> Fallback = new();
- public override TypeId StaticTypeId => TypeId.List;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override List<DateTime> DefaultValue => null!;
- public override bool IsNone(in List<DateTime> value) => value is null;
-
public override void WriteData(WriteContext context, in List<DateTime>
value, bool hasGenerics)
{
List<DateTime> list = value ?? [];
@@ -255,16 +236,11 @@ internal sealed class ListTimeSpanSerializer :
Serializer<List<TimeSpan>>
{
private static readonly ListSerializer<TimeSpan> Fallback = new();
- public override TypeId StaticTypeId => TypeId.List;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override List<TimeSpan> DefaultValue => null!;
- public override bool IsNone(in List<TimeSpan> value) => value is null;
-
public override void WriteData(WriteContext context, in List<TimeSpan>
value, bool hasGenerics)
{
List<TimeSpan> list = value ?? [];
diff --git a/csharp/src/Fory/TypeId.cs b/csharp/src/Fory/TypeId.cs
index 47857e091..da6d94cff 100644
--- a/csharp/src/Fory/TypeId.cs
+++ b/csharp/src/Fory/TypeId.cs
@@ -80,24 +80,6 @@ public enum TypeId : uint
internal static class TypeIdExtensions
{
- public static bool IsUserTypeKind(this TypeId typeId)
- {
- return typeId switch
- {
- TypeId.Enum or
- TypeId.NamedEnum or
- TypeId.Struct or
- TypeId.CompatibleStruct or
- TypeId.NamedStruct or
- TypeId.NamedCompatibleStruct or
- TypeId.Ext or
- TypeId.NamedExt or
- TypeId.TypedUnion or
- TypeId.NamedUnion => true,
- _ => false,
- };
- }
-
public static bool NeedsTypeInfoForField(this TypeId typeId)
{
return typeId switch
@@ -113,4 +95,3 @@ internal static class TypeIdExtensions
};
}
}
-
diff --git a/csharp/src/Fory/TypeInfo.cs b/csharp/src/Fory/TypeInfo.cs
index 270fa1e20..f6262b22e 100644
--- a/csharp/src/Fory/TypeInfo.cs
+++ b/csharp/src/Fory/TypeInfo.cs
@@ -15,32 +15,464 @@
// specific language governing permissions and limitations
// under the License.
+using System.Collections.Concurrent;
+using System.Collections.Immutable;
+using System.Reflection;
+
namespace Apache.Fory;
+internal enum UserTypeKind
+{
+ Enum,
+ Struct,
+ Ext,
+ TypedUnion,
+}
+
public sealed class TypeInfo
{
- internal TypeInfo(Type type, Serializer serializer)
+ private readonly object _serializer;
+ private readonly Action<WriteContext, object?, bool> _writeDataObject;
+ private readonly Func<ReadContext, object?> _readDataObject;
+ private readonly Action<WriteContext, object?, RefMode, bool, bool>
_writeObject;
+ private readonly Func<ReadContext, RefMode, bool, object?> _readObject;
+ private readonly Func<bool, IReadOnlyList<TypeMetaFieldInfo>>
_compatibleTypeMetaFields;
+ private static readonly IReadOnlyList<TypeMetaFieldInfo>
EmptyTypeMetaFields = Array.Empty<TypeMetaFieldInfo>();
+
+ private TypeInfo(
+ Type type,
+ object serializer,
+ TypeId? builtInTypeId,
+ UserTypeKind? userTypeKind,
+ bool isDynamicType,
+ bool isNullableType,
+ bool isReferenceTrackableType,
+ object? defaultObject,
+ Action<WriteContext, object?, bool> writeDataObject,
+ Func<ReadContext, object?> readDataObject,
+ Action<WriteContext, object?, RefMode, bool, bool> writeObject,
+ Func<ReadContext, RefMode, bool, object?> readObject,
+ Func<bool, IReadOnlyList<TypeMetaFieldInfo>> compatibleTypeMetaFields)
{
Type = type;
- Serializer = serializer;
- StaticTypeId = serializer.StaticTypeId;
- IsNullableType = serializer.IsNullableType;
- IsReferenceTrackableType = serializer.IsReferenceTrackableType;
+ _serializer = serializer;
+ BuiltInTypeId = builtInTypeId;
+ UserTypeKind = userTypeKind;
+ IsDynamicType = isDynamicType;
+ IsNullableType = isNullableType;
+ IsReferenceTrackableType = isReferenceTrackableType;
+ DefaultObject = defaultObject;
+ _writeDataObject = writeDataObject;
+ _readDataObject = readDataObject;
+ _writeObject = writeObject;
+ _readObject = readObject;
+ _compatibleTypeMetaFields = compatibleTypeMetaFields;
+ }
+
+ internal static TypeInfo Create<T>(Type type, Serializer<T> serializer)
+ {
+ Func<bool, IReadOnlyList<TypeMetaFieldInfo>> compatibleTypeMetaFields =
+ CreateCompatibleTypeMetaFieldsProvider(serializer, out bool
hasCompatibleTypeMetaFieldsProvider);
+ (TypeId? builtInTypeId, UserTypeKind? userTypeKind, bool
isDynamicType) = ResolveTypeShape(
+ type,
+ hasCompatibleTypeMetaFieldsProvider);
+ bool isNullableType = !type.IsValueType ||
Nullable.GetUnderlyingType(type) is not null;
+ bool isReferenceTrackableType = type != typeof(string) &&
!type.IsValueType;
+ return new TypeInfo(
+ type,
+ serializer,
+ builtInTypeId,
+ userTypeKind,
+ isDynamicType,
+ isNullableType,
+ isReferenceTrackableType,
+ serializer.DefaultObject,
+ (context, value, hasGenerics) => WriteDataObject(serializer,
context, value, hasGenerics),
+ context => serializer.ReadData(context),
+ (context, value, refMode, writeTypeInfo, hasGenerics) =>
+ WriteObject(serializer, context, value, refMode,
writeTypeInfo, hasGenerics),
+ (context, refMode, readTypeInfo) => serializer.Read(context,
refMode, readTypeInfo),
+ compatibleTypeMetaFields);
+ }
+
+ private static Func<bool, IReadOnlyList<TypeMetaFieldInfo>>
CreateCompatibleTypeMetaFieldsProvider(
+ object serializer,
+ out bool hasProvider)
+ {
+ MethodInfo? method = serializer.GetType().GetMethod(
+ "CompatibleTypeMetaFields",
+ BindingFlags.Instance | BindingFlags.Public |
BindingFlags.NonPublic,
+ null,
+ [typeof(bool)],
+ null);
+ if (method is null || method.ReturnType !=
typeof(IReadOnlyList<TypeMetaFieldInfo>))
+ {
+ hasProvider = false;
+ return EmptyCompatibleTypeMetaFields;
+ }
+
+ try
+ {
+ Delegate del = method.CreateDelegate(typeof(Func<bool,
IReadOnlyList<TypeMetaFieldInfo>>), serializer);
+ hasProvider = true;
+ return (Func<bool, IReadOnlyList<TypeMetaFieldInfo>>)del;
+ }
+ catch
+ {
+ hasProvider = false;
+ return EmptyCompatibleTypeMetaFields;
+ }
+ }
+
+ private static IReadOnlyList<TypeMetaFieldInfo>
EmptyCompatibleTypeMetaFields(bool _)
+ {
+ return EmptyTypeMetaFields;
+ }
+
+ private static void WriteDataObject<T>(Serializer<T> serializer,
WriteContext context, object? value, bool hasGenerics)
+ {
+ serializer.WriteData(context, CoerceRuntimeValue(serializer, value),
hasGenerics);
+ }
+
+ private static void WriteObject<T>(
+ Serializer<T> serializer,
+ WriteContext context,
+ object? value,
+ RefMode refMode,
+ bool writeTypeInfo,
+ bool hasGenerics)
+ {
+ serializer.Write(context, CoerceRuntimeValue(serializer, value),
refMode, writeTypeInfo, hasGenerics);
+ }
+
+ private static T CoerceRuntimeValue<T>(Serializer<T> serializer, object?
value)
+ {
+ if (value is T typed)
+ {
+ return typed;
+ }
+
+ if (value is null && default(T) is null)
+ {
+ return serializer.DefaultValue;
+ }
+
+ throw new InvalidDataException(
+ $"serializer {serializer.GetType().Name} expected value of type
{typeof(T)}, got {value?.GetType()}");
+ }
+
+ private static (TypeId? BuiltInTypeId, UserTypeKind? UserTypeKind, bool
IsDynamicType) ResolveTypeShape(
+ Type type,
+ bool hasCompatibleTypeMetaFieldsProvider)
+ {
+ Type? nullableType = Nullable.GetUnderlyingType(type);
+ if (nullableType is not null)
+ {
+ return ResolveTypeShape(nullableType,
hasCompatibleTypeMetaFieldsProvider);
+ }
+
+ if (TryResolveBuiltInTypeId(type, out TypeId builtInTypeId))
+ {
+ return (builtInTypeId, null, false);
+ }
+
+ if (type == typeof(object))
+ {
+ return (null, null, true);
+ }
+
+ if (type.IsEnum)
+ {
+ return (null, Apache.Fory.UserTypeKind.Enum, false);
+ }
+
+ if (typeof(Union).IsAssignableFrom(type))
+ {
+ return (null, Apache.Fory.UserTypeKind.TypedUnion, false);
+ }
+
+ if (hasCompatibleTypeMetaFieldsProvider)
+ {
+ return (null, Apache.Fory.UserTypeKind.Struct, false);
+ }
+
+ return (null, Apache.Fory.UserTypeKind.Ext, false);
+ }
+
+ private static bool TryResolveBuiltInTypeId(Type type, out TypeId typeId)
+ {
+ if (type == typeof(bool))
+ {
+ typeId = TypeId.Bool;
+ return true;
+ }
+
+ if (type == typeof(sbyte))
+ {
+ typeId = TypeId.Int8;
+ return true;
+ }
+
+ if (type == typeof(short))
+ {
+ typeId = TypeId.Int16;
+ return true;
+ }
+
+ if (type == typeof(int))
+ {
+ typeId = TypeId.VarInt32;
+ return true;
+ }
+
+ if (type == typeof(long))
+ {
+ typeId = TypeId.VarInt64;
+ return true;
+ }
+
+ if (type == typeof(byte))
+ {
+ typeId = TypeId.UInt8;
+ return true;
+ }
+
+ if (type == typeof(ushort))
+ {
+ typeId = TypeId.UInt16;
+ return true;
+ }
+
+ if (type == typeof(uint))
+ {
+ typeId = TypeId.VarUInt32;
+ return true;
+ }
+
+ if (type == typeof(ulong))
+ {
+ typeId = TypeId.VarUInt64;
+ return true;
+ }
+
+ if (type == typeof(float))
+ {
+ typeId = TypeId.Float32;
+ return true;
+ }
+
+ if (type == typeof(double))
+ {
+ typeId = TypeId.Float64;
+ return true;
+ }
+
+ if (type == typeof(string))
+ {
+ typeId = TypeId.String;
+ return true;
+ }
+
+ if (type == typeof(byte[]))
+ {
+ typeId = TypeId.Binary;
+ return true;
+ }
+
+ if (type == typeof(bool[]))
+ {
+ typeId = TypeId.BoolArray;
+ return true;
+ }
+
+ if (type == typeof(sbyte[]))
+ {
+ typeId = TypeId.Int8Array;
+ return true;
+ }
+
+ if (type == typeof(short[]))
+ {
+ typeId = TypeId.Int16Array;
+ return true;
+ }
+
+ if (type == typeof(int[]))
+ {
+ typeId = TypeId.Int32Array;
+ return true;
+ }
+
+ if (type == typeof(long[]))
+ {
+ typeId = TypeId.Int64Array;
+ return true;
+ }
+
+ if (type == typeof(ushort[]))
+ {
+ typeId = TypeId.UInt16Array;
+ return true;
+ }
+
+ if (type == typeof(uint[]))
+ {
+ typeId = TypeId.UInt32Array;
+ return true;
+ }
+
+ if (type == typeof(ulong[]))
+ {
+ typeId = TypeId.UInt64Array;
+ return true;
+ }
+
+ if (type == typeof(float[]))
+ {
+ typeId = TypeId.Float32Array;
+ return true;
+ }
+
+ if (type == typeof(double[]))
+ {
+ typeId = TypeId.Float64Array;
+ return true;
+ }
+
+ if (type == typeof(DateOnly))
+ {
+ typeId = TypeId.Date;
+ return true;
+ }
+
+ if (type == typeof(DateTimeOffset) || type == typeof(DateTime))
+ {
+ typeId = TypeId.Timestamp;
+ return true;
+ }
+
+ if (type == typeof(TimeSpan))
+ {
+ typeId = TypeId.Duration;
+ return true;
+ }
+
+ if (type.IsArray)
+ {
+ typeId = TypeId.List;
+ return true;
+ }
+
+ if (type.IsGenericType)
+ {
+ Type genericType = type.GetGenericTypeDefinition();
+ if (genericType == typeof(List<>) ||
+ genericType == typeof(LinkedList<>) ||
+ genericType == typeof(Queue<>) ||
+ genericType == typeof(Stack<>))
+ {
+ typeId = TypeId.List;
+ return true;
+ }
+
+ if (genericType == typeof(HashSet<>) ||
+ genericType == typeof(SortedSet<>) ||
+ genericType == typeof(ImmutableHashSet<>))
+ {
+ typeId = TypeId.Set;
+ return true;
+ }
+
+ if (genericType == typeof(Dictionary<,>) ||
+ genericType == typeof(SortedDictionary<,>) ||
+ genericType == typeof(SortedList<,>) ||
+ genericType == typeof(ConcurrentDictionary<,>) ||
+ genericType == typeof(NullableKeyDictionary<,>))
+ {
+ typeId = TypeId.Map;
+ return true;
+ }
+
+ if (genericType == typeof(Nullable<>))
+ {
+ Type? underlying = Nullable.GetUnderlyingType(type);
+ if (underlying is not null)
+ {
+ return TryResolveBuiltInTypeId(underlying, out typeId);
+ }
+ }
+ }
+
+ typeId = default;
+ return false;
}
public Type Type { get; }
- internal Serializer Serializer { get; }
+ public bool IsBuiltinType => BuiltInTypeId.HasValue;
+
+ public TypeId? BuiltInTypeId { get; }
+
+ public bool IsUserType => UserTypeKind.HasValue;
- public TypeId StaticTypeId { get; }
+ internal UserTypeKind? UserTypeKind { get; }
+
+ public bool IsDynamicType { get; }
public bool IsNullableType { get; }
public bool IsReferenceTrackableType { get; }
- public void WriteObject(WriteContext context, object? value, RefMode
refMode, bool writeTypeInfo, bool hasGenerics)
+ public object? DefaultObject { get; }
+
+ public bool NeedsTypeInfoForField()
+ {
+ if (IsDynamicType)
+ {
+ return true;
+ }
+
+ if (!UserTypeKind.HasValue)
+ {
+ return false;
+ }
+
+ return UserTypeKind.Value is Apache.Fory.UserTypeKind.Struct or
Apache.Fory.UserTypeKind.Ext;
+ }
+
+ internal Serializer<T> RequireSerializer<T>()
+ {
+ if (_serializer is Serializer<T> serializer)
+ {
+ return serializer;
+ }
+
+ throw new InvalidDataException($"serializer type mismatch for
{typeof(T)}");
+ }
+
+ internal void WriteDataObject(WriteContext context, object? value, bool
hasGenerics)
+ {
+ _writeDataObject(context, value, hasGenerics);
+ }
+
+ internal object? ReadDataObject(ReadContext context)
+ {
+ return _readDataObject(context);
+ }
+
+ internal void WriteObject(WriteContext context, object? value, RefMode
refMode, bool writeTypeInfo, bool hasGenerics)
+ {
+ _writeObject(context, value, refMode, writeTypeInfo, hasGenerics);
+ }
+
+ internal object? ReadObject(ReadContext context, RefMode refMode, bool
readTypeInfo)
+ {
+ return _readObject(context, refMode, readTypeInfo);
+ }
+
+ internal IReadOnlyList<TypeMetaFieldInfo> CompatibleTypeMetaFields(bool
trackRef)
{
- Serializer.WriteObject(context, value, refMode, writeTypeInfo,
hasGenerics);
+ return _compatibleTypeMetaFields(trackRef);
}
internal bool IsRegistered { get; private set; }
diff --git a/csharp/src/Fory/TypeResolver.cs b/csharp/src/Fory/TypeResolver.cs
index 62fd83c6c..2f8b8ee72 100644
--- a/csharp/src/Fory/TypeResolver.cs
+++ b/csharp/src/Fory/TypeResolver.cs
@@ -17,13 +17,22 @@
using System.Collections.Concurrent;
using System.Collections.Immutable;
+using System.Reflection;
namespace Apache.Fory;
public sealed class TypeResolver
{
- private static readonly ConcurrentDictionary<Type, Func<Serializer>>
GeneratedFactories = new();
+ private static readonly ConcurrentDictionary<Type, Func<TypeResolver,
TypeInfo>> GeneratedFactories = new();
private static readonly ConcurrentDictionary<TypeId, HashSet<TypeId>>
SingleAllowedWireTypes = new();
+ private static readonly MethodInfo CreateTypeInfoFromSerializerTypedMethod
=
+ typeof(TypeResolver).GetMethod(
+ nameof(CreateTypeInfoFromSerializerTyped),
+ BindingFlags.NonPublic | BindingFlags.Static)!;
+ private static readonly MethodInfo CreateNullableSerializerTypeInfoMethod =
+ typeof(TypeResolver).GetMethod(
+ nameof(CreateNullableSerializerTypeInfo),
+ BindingFlags.NonPublic | BindingFlags.Instance)!;
private static readonly HashSet<TypeId> CompatibleStructAllowedWireTypes =
[
TypeId.Struct,
@@ -90,12 +99,12 @@ public sealed class TypeResolver
where TSerializer : Serializer<T>, new()
{
Type type = typeof(T);
- GeneratedFactories[type] = CreateSerializer<TSerializer>;
+ GeneratedFactories[type] = static _ => TypeInfo.Create(typeof(T), new
TSerializer());
}
public Serializer<T> GetSerializer<T>()
{
- return GetTypeInfo<T>().Serializer.RequireSerializer<T>();
+ return GetTypeInfo<T>().RequireSerializer<T>();
}
public TypeInfo GetTypeInfo(Type type)
@@ -108,11 +117,63 @@ public sealed class TypeResolver
return GetTypeInfo(typeof(T));
}
- private TypeInfo GetOrCreateTypeInfo(Type type, Serializer?
explicitSerializer)
+ internal bool IsNoneObject(TypeInfo typeInfo, object? value)
+ {
+ return typeInfo.IsNullableType && value is null;
+ }
+
+ internal void WriteDataObject(TypeInfo typeInfo, WriteContext context,
object? value, bool hasGenerics)
+ {
+ typeInfo.WriteDataObject(context, value, hasGenerics);
+ }
+
+ internal object? ReadDataObject(TypeInfo typeInfo, ReadContext context)
+ {
+ return typeInfo.ReadDataObject(context);
+ }
+
+ public void WriteObject(
+ TypeInfo typeInfo,
+ WriteContext context,
+ object? value,
+ RefMode refMode,
+ bool writeTypeInfo,
+ bool hasGenerics)
+ {
+ typeInfo.WriteObject(context, value, refMode, writeTypeInfo,
hasGenerics);
+ }
+
+ internal object? ReadObject(TypeInfo typeInfo, ReadContext context,
RefMode refMode, bool readTypeInfo)
+ {
+ return typeInfo.ReadObject(context, refMode, readTypeInfo);
+ }
+
+ internal void WriteTypeInfo(TypeInfo typeInfo, WriteContext context)
+ {
+ WriteTypeInfoCore(typeInfo.Type, typeInfo, context);
+ }
+
+ internal void ReadTypeInfo(TypeInfo typeInfo, ReadContext context)
+ {
+ ReadTypeInfoCore(typeInfo.Type, typeInfo, context);
+ }
+
+ internal IReadOnlyList<TypeMetaFieldInfo>
CompatibleTypeMetaFields(TypeInfo typeInfo, bool trackRef)
+ {
+ Type? nullableType = Nullable.GetUnderlyingType(typeInfo.Type);
+ if (nullableType is not null)
+ {
+ return CompatibleTypeMetaFields(GetTypeInfo(nullableType),
trackRef);
+ }
+
+ return typeInfo.CompatibleTypeMetaFields(trackRef);
+ }
+
+ private TypeInfo GetOrCreateTypeInfo(Type type, TypeInfo? explicitTypeInfo)
{
if (_typeInfos.TryGetValue(type, out TypeInfo? existing))
{
- if (explicitSerializer is null ||
ReferenceEquals(existing.Serializer, explicitSerializer))
+ if (explicitTypeInfo is null || ReferenceEquals(existing,
explicitTypeInfo))
{
return existing;
}
@@ -123,8 +184,12 @@ public sealed class TypeResolver
}
}
- Serializer serializer = explicitSerializer ?? CreateBindingCore(type);
- TypeInfo typeInfo = new(type, serializer);
+ TypeInfo typeInfo = explicitTypeInfo ?? CreateBindingCore(type);
+ if (typeInfo.Type != type)
+ {
+ throw new InvalidDataException($"serializer type mismatch for
{type}, got {typeInfo.Type}");
+ }
+
if (_typeInfos.TryGetValue(type, out TypeInfo? previous))
{
typeInfo.CopyRegistrationFrom(previous);
@@ -134,34 +199,29 @@ public sealed class TypeResolver
return typeInfo;
}
- internal Serializer GetSerializer(Type type)
- {
- return GetOrCreateTypeInfo(type, null).Serializer;
- }
-
- internal Serializer RegisterSerializer<T, TSerializer>()
+ internal TypeInfo RegisterSerializer<T, TSerializer>()
where TSerializer : Serializer<T>, new()
{
- Serializer serializer = CreateSerializer<TSerializer>();
- RegisterSerializer(typeof(T), serializer);
- return serializer;
+ TypeInfo typeInfo = TypeInfo.Create(typeof(T), new TSerializer());
+ RegisterSerializer(typeof(T), typeInfo);
+ return typeInfo;
}
- internal void RegisterSerializer(Type type, Serializer serializer)
+ internal void RegisterSerializer(Type type, TypeInfo typeInfo)
{
- GetOrCreateTypeInfo(type, serializer);
+ GetOrCreateTypeInfo(type, typeInfo);
}
- internal void Register(Type type, uint id, Serializer? explicitSerializer
= null)
+ internal void Register(Type type, uint id, TypeInfo? explicitTypeInfo =
null)
{
- TypeInfo typeInfo = GetOrCreateTypeInfo(type, explicitSerializer);
+ TypeInfo typeInfo = GetOrCreateTypeInfo(type, explicitTypeInfo);
typeInfo.RegisterByTypeId(id);
_byUserTypeId[id] = typeInfo;
}
- internal void Register(Type type, string namespaceName, string typeName,
Serializer? explicitSerializer = null)
+ internal void Register(Type type, string namespaceName, string typeName,
TypeInfo? explicitTypeInfo = null)
{
- TypeInfo typeInfo = GetOrCreateTypeInfo(type, explicitSerializer);
+ TypeInfo typeInfo = GetOrCreateTypeInfo(type, explicitTypeInfo);
MetaString namespaceMeta =
MetaStringEncoder.Namespace.Encode(namespaceName,
TypeMetaEncodings.NamespaceMetaStringEncodings);
MetaString typeNameMeta = MetaStringEncoder.TypeName.Encode(typeName,
TypeMetaEncodings.TypeNameMetaStringEncodings);
typeInfo.RegisterByTypeName(namespaceMeta, typeNameMeta);
@@ -189,17 +249,45 @@ public sealed class TypeResolver
throw new TypeNotRegisteredException($"{type} is not registered");
}
- internal void WriteTypeInfo(Type type, Serializer serializer, WriteContext
context)
+ internal void WriteTypeInfo<T>(Serializer<T> serializer, WriteContext
context)
+ {
+ Type type = typeof(T);
+ if (type == typeof(object))
+ {
+ throw new InvalidDataException("dynamic Any value type info is
runtime-only");
+ }
+
+ Type? nullableType = Nullable.GetUnderlyingType(type);
+ if (nullableType is not null)
+ {
+ WriteTypeInfoCore(nullableType, GetTypeInfo(nullableType),
context);
+ return;
+ }
+
+ TypeInfo typeInfo = GetTypeInfo<T>();
+ WriteTypeInfoCore(type, typeInfo, context);
+ }
+
+ private void WriteTypeInfoCore(Type type, TypeInfo typeInfo, WriteContext
context)
{
- TypeId staticTypeId = serializer.StaticTypeId;
- if (!staticTypeId.IsUserTypeKind())
+ if (typeInfo.BuiltInTypeId.HasValue)
{
- context.Writer.WriteUInt8((byte)staticTypeId);
+ context.Writer.WriteUInt8((byte)typeInfo.BuiltInTypeId.Value);
return;
}
+ if (!typeInfo.UserTypeKind.HasValue)
+ {
+ throw new InvalidDataException($"type {type} has runtime-only type
info");
+ }
+
TypeInfo info = RequireRegisteredTypeInfo(type);
- TypeId wireTypeId = ResolveWireTypeId(info.StaticTypeId,
info.RegisterByName, context.Compatible);
+ if (!info.UserTypeKind.HasValue)
+ {
+ throw new InvalidDataException($"registered type {type} is not a
user type");
+ }
+
+ TypeId wireTypeId = ResolveWireTypeId(info.UserTypeKind.Value,
info.RegisterByName, context.Compatible);
context.Writer.WriteUInt8((byte)wireTypeId);
switch (wireTypeId)
{
@@ -256,7 +344,28 @@ public sealed class TypeResolver
}
}
- internal void ReadTypeInfo(Type type, Serializer serializer, ReadContext
context)
+ internal void ReadTypeInfo<T>(Serializer<T> serializer, ReadContext
context)
+ {
+ Type type = typeof(T);
+ if (type == typeof(object))
+ {
+ DynamicTypeInfo dynamicTypeInfo = ReadDynamicTypeInfo(context);
+ context.SetDynamicTypeInfo(type, dynamicTypeInfo);
+ return;
+ }
+
+ Type? nullableType = Nullable.GetUnderlyingType(type);
+ if (nullableType is not null)
+ {
+ ReadTypeInfoCore(nullableType, GetTypeInfo(nullableType), context);
+ return;
+ }
+
+ TypeInfo typeInfo = GetTypeInfo<T>();
+ ReadTypeInfoCore(type, typeInfo, context);
+ }
+
+ private void ReadTypeInfoCore(Type type, TypeInfo typeInfo, ReadContext
context)
{
uint rawTypeId = context.Reader.ReadVarUInt32();
if (!Enum.IsDefined(typeof(TypeId), rawTypeId))
@@ -265,19 +374,28 @@ public sealed class TypeResolver
}
TypeId typeId = (TypeId)rawTypeId;
- TypeId staticTypeId = serializer.StaticTypeId;
- if (!staticTypeId.IsUserTypeKind())
+ if (typeInfo.BuiltInTypeId.HasValue)
{
- if (typeId != staticTypeId)
+ if (typeId != typeInfo.BuiltInTypeId.Value)
{
- throw new TypeMismatchException((uint)staticTypeId, rawTypeId);
+ throw new
TypeMismatchException((uint)typeInfo.BuiltInTypeId.Value, rawTypeId);
}
return;
}
+ if (!typeInfo.UserTypeKind.HasValue)
+ {
+ throw new InvalidDataException($"type {type} has runtime-only type
info");
+ }
+
TypeInfo info = RequireRegisteredTypeInfo(type);
- HashSet<TypeId> allowed = AllowedWireTypeIds(info.StaticTypeId,
info.RegisterByName, context.Compatible);
+ if (!info.UserTypeKind.HasValue)
+ {
+ throw new InvalidDataException($"registered type {type} is not a
user type");
+ }
+
+ HashSet<TypeId> allowed = AllowedWireTypeIds(info.UserTypeKind.Value,
info.RegisterByName, context.Compatible);
if (!allowed.Contains(typeId))
{
uint expected = 0;
@@ -357,21 +475,33 @@ public sealed class TypeResolver
}
}
- internal static TypeId ResolveWireTypeId(TypeId declaredKind, bool
registerByName, bool compatible)
+ internal static TypeId ResolveWireTypeId(UserTypeKind declaredKind, bool
registerByName, bool compatible)
{
- TypeId baseKind = NormalizeBaseKind(declaredKind);
if (registerByName)
{
- return NamedKind(baseKind, compatible);
+ return declaredKind switch
+ {
+ UserTypeKind.Struct => compatible ?
TypeId.NamedCompatibleStruct : TypeId.NamedStruct,
+ UserTypeKind.Enum => TypeId.NamedEnum,
+ UserTypeKind.Ext => TypeId.NamedExt,
+ UserTypeKind.TypedUnion => TypeId.NamedUnion,
+ _ => throw new InvalidDataException($"unknown user type kind
{declaredKind}"),
+ };
}
- return IdKind(baseKind, compatible);
+ return declaredKind switch
+ {
+ UserTypeKind.Struct => compatible ? TypeId.CompatibleStruct :
TypeId.Struct,
+ UserTypeKind.Enum => TypeId.Enum,
+ UserTypeKind.Ext => TypeId.Ext,
+ UserTypeKind.TypedUnion => TypeId.TypedUnion,
+ _ => throw new InvalidDataException($"unknown user type kind
{declaredKind}"),
+ };
}
- internal static HashSet<TypeId> AllowedWireTypeIds(TypeId declaredKind,
bool registerByName, bool compatible)
+ internal static HashSet<TypeId> AllowedWireTypeIds(UserTypeKind
declaredKind, bool registerByName, bool compatible)
{
- TypeId baseKind = NormalizeBaseKind(declaredKind);
- if (baseKind == TypeId.Struct && compatible)
+ if (declaredKind == UserTypeKind.Struct && compatible)
{
return CompatibleStructAllowedWireTypes;
}
@@ -400,14 +530,14 @@ public sealed class TypeResolver
return ReadRegisteredValue(typeInfo, context, compatibleTypeMeta);
}
- private static object? ReadRegisteredValue(TypeInfo typeInfo, ReadContext
context, TypeMeta? compatibleTypeMeta)
+ private object? ReadRegisteredValue(TypeInfo typeInfo, ReadContext
context, TypeMeta? compatibleTypeMeta)
{
if (compatibleTypeMeta is not null)
{
context.PushCompatibleTypeMeta(typeInfo.Type, compatibleTypeMeta);
}
- return typeInfo.Serializer.ReadObject(context, RefMode.None, false);
+ return ReadObject(typeInfo, context, RefMode.None, false);
}
public DynamicTypeInfo ReadDynamicTypeInfo(ReadContext context)
@@ -752,50 +882,17 @@ public sealed class TypeResolver
return values;
}
- private static TypeId NormalizeBaseKind(TypeId kind)
- {
- return kind switch
- {
- TypeId.NamedEnum => TypeId.Enum,
- TypeId.CompatibleStruct or TypeId.NamedCompatibleStruct or
TypeId.NamedStruct => TypeId.Struct,
- TypeId.NamedExt => TypeId.Ext,
- TypeId.NamedUnion => TypeId.TypedUnion,
- _ => kind,
- };
- }
-
- private static TypeId NamedKind(TypeId baseKind, bool compatible)
- {
- return baseKind switch
- {
- TypeId.Struct => compatible ? TypeId.NamedCompatibleStruct :
TypeId.NamedStruct,
- TypeId.Enum => TypeId.NamedEnum,
- TypeId.Ext => TypeId.NamedExt,
- TypeId.TypedUnion => TypeId.NamedUnion,
- _ => baseKind,
- };
- }
-
- private static TypeId IdKind(TypeId baseKind, bool compatible)
- {
- return baseKind switch
- {
- TypeId.Struct => compatible ? TypeId.CompatibleStruct :
TypeId.Struct,
- _ => baseKind,
- };
- }
-
private static bool WireTypeNeedsUserTypeId(TypeId typeId)
{
return typeId is TypeId.Enum or TypeId.Struct or TypeId.Ext or
TypeId.TypedUnion;
}
- private static TypeMeta BuildCompatibleTypeMeta(
+ private TypeMeta BuildCompatibleTypeMeta(
TypeInfo info,
TypeId wireTypeId,
bool trackRef)
{
- IReadOnlyList<TypeMetaFieldInfo> fields =
info.Serializer.CompatibleTypeMetaFields(trackRef);
+ IReadOnlyList<TypeMetaFieldInfo> fields =
CompatibleTypeMetaFields(info, trackRef);
bool hasFieldsMeta = fields.Count > 0;
if (info.RegisterByName)
{
@@ -998,312 +1095,312 @@ public sealed class TypeResolver
return result;
}
- private Serializer CreateBindingCore(Type type)
+ private TypeInfo CreateBindingCore(Type type)
{
- if (GeneratedFactories.TryGetValue(type, out Func<Serializer>?
generatedFactory))
+ if (GeneratedFactories.TryGetValue(type, out Func<TypeResolver,
TypeInfo>? generatedFactory))
{
- return generatedFactory();
+ return generatedFactory(this);
}
if (type == typeof(bool))
{
- return new BoolSerializer();
+ return TypeInfo.Create(type, new BoolSerializer());
}
if (type == typeof(sbyte))
{
- return new Int8Serializer();
+ return TypeInfo.Create(type, new Int8Serializer());
}
if (type == typeof(short))
{
- return new Int16Serializer();
+ return TypeInfo.Create(type, new Int16Serializer());
}
if (type == typeof(int))
{
- return new Int32Serializer();
+ return TypeInfo.Create(type, new Int32Serializer());
}
if (type == typeof(long))
{
- return new Int64Serializer();
+ return TypeInfo.Create(type, new Int64Serializer());
}
if (type == typeof(byte))
{
- return new UInt8Serializer();
+ return TypeInfo.Create(type, new UInt8Serializer());
}
if (type == typeof(ushort))
{
- return new UInt16Serializer();
+ return TypeInfo.Create(type, new UInt16Serializer());
}
if (type == typeof(uint))
{
- return new UInt32Serializer();
+ return TypeInfo.Create(type, new UInt32Serializer());
}
if (type == typeof(ulong))
{
- return new UInt64Serializer();
+ return TypeInfo.Create(type, new UInt64Serializer());
}
if (type == typeof(float))
{
- return new Float32Serializer();
+ return TypeInfo.Create(type, new Float32Serializer());
}
if (type == typeof(double))
{
- return new Float64Serializer();
+ return TypeInfo.Create(type, new Float64Serializer());
}
if (type == typeof(string))
{
- return new StringSerializer();
+ return TypeInfo.Create(type, new StringSerializer());
}
if (type == typeof(byte[]))
{
- return new BinarySerializer();
+ return TypeInfo.Create(type, new BinarySerializer());
}
if (type == typeof(bool[]))
{
- return new BoolArraySerializer();
+ return TypeInfo.Create(type, new BoolArraySerializer());
}
if (type == typeof(sbyte[]))
{
- return new Int8ArraySerializer();
+ return TypeInfo.Create(type, new Int8ArraySerializer());
}
if (type == typeof(short[]))
{
- return new Int16ArraySerializer();
+ return TypeInfo.Create(type, new Int16ArraySerializer());
}
if (type == typeof(int[]))
{
- return new Int32ArraySerializer();
+ return TypeInfo.Create(type, new Int32ArraySerializer());
}
if (type == typeof(long[]))
{
- return new Int64ArraySerializer();
+ return TypeInfo.Create(type, new Int64ArraySerializer());
}
if (type == typeof(ushort[]))
{
- return new UInt16ArraySerializer();
+ return TypeInfo.Create(type, new UInt16ArraySerializer());
}
if (type == typeof(uint[]))
{
- return new UInt32ArraySerializer();
+ return TypeInfo.Create(type, new UInt32ArraySerializer());
}
if (type == typeof(ulong[]))
{
- return new UInt64ArraySerializer();
+ return TypeInfo.Create(type, new UInt64ArraySerializer());
}
if (type == typeof(float[]))
{
- return new Float32ArraySerializer();
+ return TypeInfo.Create(type, new Float32ArraySerializer());
}
if (type == typeof(double[]))
{
- return new Float64ArraySerializer();
+ return TypeInfo.Create(type, new Float64ArraySerializer());
}
if (type == typeof(DateOnly))
{
- return new DateOnlySerializer();
+ return TypeInfo.Create(type, new DateOnlySerializer());
}
if (type == typeof(DateTimeOffset))
{
- return new DateTimeOffsetSerializer();
+ return TypeInfo.Create(type, new DateTimeOffsetSerializer());
}
if (type == typeof(DateTime))
{
- return new DateTimeSerializer();
+ return TypeInfo.Create(type, new DateTimeSerializer());
}
if (type == typeof(TimeSpan))
{
- return new TimeSpanSerializer();
+ return TypeInfo.Create(type, new TimeSpanSerializer());
}
if (type == typeof(List<bool>))
{
- return new ListBoolSerializer();
+ return TypeInfo.Create(type, new ListBoolSerializer());
}
if (type == typeof(List<sbyte>))
{
- return new ListInt8Serializer();
+ return TypeInfo.Create(type, new ListInt8Serializer());
}
if (type == typeof(List<short>))
{
- return new ListInt16Serializer();
+ return TypeInfo.Create(type, new ListInt16Serializer());
}
if (type == typeof(List<int>))
{
- return new ListIntSerializer();
+ return TypeInfo.Create(type, new ListIntSerializer());
}
if (type == typeof(List<long>))
{
- return new ListLongSerializer();
+ return TypeInfo.Create(type, new ListLongSerializer());
}
if (type == typeof(List<byte>))
{
- return new ListUInt8Serializer();
+ return TypeInfo.Create(type, new ListUInt8Serializer());
}
if (type == typeof(List<ushort>))
{
- return new ListUInt16Serializer();
+ return TypeInfo.Create(type, new ListUInt16Serializer());
}
if (type == typeof(List<uint>))
{
- return new ListUIntSerializer();
+ return TypeInfo.Create(type, new ListUIntSerializer());
}
if (type == typeof(List<ulong>))
{
- return new ListULongSerializer();
+ return TypeInfo.Create(type, new ListULongSerializer());
}
if (type == typeof(List<float>))
{
- return new ListFloatSerializer();
+ return TypeInfo.Create(type, new ListFloatSerializer());
}
if (type == typeof(List<double>))
{
- return new ListDoubleSerializer();
+ return TypeInfo.Create(type, new ListDoubleSerializer());
}
if (type == typeof(List<string>))
{
- return new ListStringSerializer();
+ return TypeInfo.Create(type, new ListStringSerializer());
}
if (type == typeof(List<DateOnly>))
{
- return new ListDateOnlySerializer();
+ return TypeInfo.Create(type, new ListDateOnlySerializer());
}
if (type == typeof(List<DateTimeOffset>))
{
- return new ListDateTimeOffsetSerializer();
+ return TypeInfo.Create(type, new ListDateTimeOffsetSerializer());
}
if (type == typeof(List<DateTime>))
{
- return new ListDateTimeSerializer();
+ return TypeInfo.Create(type, new ListDateTimeSerializer());
}
if (type == typeof(List<TimeSpan>))
{
- return new ListTimeSpanSerializer();
+ return TypeInfo.Create(type, new ListTimeSpanSerializer());
}
if (type == typeof(HashSet<sbyte>))
{
- return new SetInt8Serializer();
+ return TypeInfo.Create(type, new SetInt8Serializer());
}
if (type == typeof(HashSet<short>))
{
- return new SetInt16Serializer();
+ return TypeInfo.Create(type, new SetInt16Serializer());
}
if (type == typeof(HashSet<int>))
{
- return new SetIntSerializer();
+ return TypeInfo.Create(type, new SetIntSerializer());
}
if (type == typeof(HashSet<long>))
{
- return new SetLongSerializer();
+ return TypeInfo.Create(type, new SetLongSerializer());
}
if (type == typeof(HashSet<byte>))
{
- return new SetUInt8Serializer();
+ return TypeInfo.Create(type, new SetUInt8Serializer());
}
if (type == typeof(HashSet<ushort>))
{
- return new SetUInt16Serializer();
+ return TypeInfo.Create(type, new SetUInt16Serializer());
}
if (type == typeof(HashSet<uint>))
{
- return new SetUIntSerializer();
+ return TypeInfo.Create(type, new SetUIntSerializer());
}
if (type == typeof(HashSet<ulong>))
{
- return new SetULongSerializer();
+ return TypeInfo.Create(type, new SetULongSerializer());
}
if (type == typeof(HashSet<float>))
{
- return new SetFloatSerializer();
+ return TypeInfo.Create(type, new SetFloatSerializer());
}
if (type == typeof(HashSet<double>))
{
- return new SetDoubleSerializer();
+ return TypeInfo.Create(type, new SetDoubleSerializer());
}
- Serializer? primitiveCollectionSerializer =
TryCreatePrimitiveCollectionSerializer(type);
- if (primitiveCollectionSerializer is not null)
+ TypeInfo? primitiveCollectionTypeInfo =
TryCreatePrimitiveCollectionTypeInfo(type);
+ if (primitiveCollectionTypeInfo is not null)
{
- return primitiveCollectionSerializer;
+ return primitiveCollectionTypeInfo;
}
- Serializer? primitiveDictionarySerializer =
TryCreatePrimitiveDictionarySerializer(type);
- if (primitiveDictionarySerializer is not null)
+ TypeInfo? primitiveDictionaryTypeInfo =
TryCreatePrimitiveDictionaryTypeInfo(type);
+ if (primitiveDictionaryTypeInfo is not null)
{
- return primitiveDictionarySerializer;
+ return primitiveDictionaryTypeInfo;
}
if (type == typeof(object))
{
- return new DynamicAnyObjectSerializer();
+ return TypeInfo.Create(type, new DynamicAnyObjectSerializer());
}
if (typeof(Union).IsAssignableFrom(type))
{
Type serializerType =
typeof(UnionSerializer<>).MakeGenericType(type);
- return CreateSerializer(serializerType);
+ return CreateTypeInfo(type, serializerType);
}
if (type.IsEnum)
{
Type serializerType =
typeof(EnumSerializer<>).MakeGenericType(type);
- return CreateSerializer(serializerType);
+ return CreateTypeInfo(type, serializerType);
}
if (type.IsArray)
{
Type elementType = type.GetElementType()!;
Type serializerType =
typeof(ArraySerializer<>).MakeGenericType(elementType);
- return CreateSerializer(serializerType);
+ return CreateTypeInfo(type, serializerType);
}
if (type.IsGenericType)
@@ -1312,87 +1409,86 @@ public sealed class TypeResolver
Type[] genericArgs = type.GetGenericArguments();
if (genericType == typeof(Nullable<>))
{
- Type serializerType =
typeof(NullableSerializer<>).MakeGenericType(genericArgs[0]);
- return CreateSerializer(serializerType);
+ return CreateNullableTypeInfo(genericArgs[0]);
}
if (genericType == typeof(List<>))
{
Type serializerType =
typeof(ListSerializer<>).MakeGenericType(genericArgs[0]);
- return CreateSerializer(serializerType);
+ return CreateTypeInfo(type, serializerType);
}
if (genericType == typeof(HashSet<>))
{
Type serializerType =
typeof(SetSerializer<>).MakeGenericType(genericArgs[0]);
- return CreateSerializer(serializerType);
+ return CreateTypeInfo(type, serializerType);
}
if (genericType == typeof(SortedSet<>))
{
Type serializerType =
typeof(SortedSetSerializer<>).MakeGenericType(genericArgs[0]);
- return CreateSerializer(serializerType);
+ return CreateTypeInfo(type, serializerType);
}
if (genericType == typeof(ImmutableHashSet<>))
{
Type serializerType =
typeof(ImmutableHashSetSerializer<>).MakeGenericType(genericArgs[0]);
- return CreateSerializer(serializerType);
+ return CreateTypeInfo(type, serializerType);
}
if (genericType == typeof(LinkedList<>))
{
Type serializerType =
typeof(LinkedListSerializer<>).MakeGenericType(genericArgs[0]);
- return CreateSerializer(serializerType);
+ return CreateTypeInfo(type, serializerType);
}
if (genericType == typeof(Queue<>))
{
Type serializerType =
typeof(QueueSerializer<>).MakeGenericType(genericArgs[0]);
- return CreateSerializer(serializerType);
+ return CreateTypeInfo(type, serializerType);
}
if (genericType == typeof(Stack<>))
{
Type serializerType =
typeof(StackSerializer<>).MakeGenericType(genericArgs[0]);
- return CreateSerializer(serializerType);
+ return CreateTypeInfo(type, serializerType);
}
if (genericType == typeof(Dictionary<,>))
{
Type serializerType =
typeof(DictionarySerializer<,>).MakeGenericType(genericArgs[0], genericArgs[1]);
- return CreateSerializer(serializerType);
+ return CreateTypeInfo(type, serializerType);
}
if (genericType == typeof(SortedDictionary<,>))
{
Type serializerType =
typeof(SortedDictionarySerializer<,>).MakeGenericType(genericArgs[0],
genericArgs[1]);
- return CreateSerializer(serializerType);
+ return CreateTypeInfo(type, serializerType);
}
if (genericType == typeof(SortedList<,>))
{
Type serializerType =
typeof(SortedListSerializer<,>).MakeGenericType(genericArgs[0], genericArgs[1]);
- return CreateSerializer(serializerType);
+ return CreateTypeInfo(type, serializerType);
}
if (genericType == typeof(ConcurrentDictionary<,>))
{
Type serializerType =
typeof(ConcurrentDictionarySerializer<,>).MakeGenericType(genericArgs[0],
genericArgs[1]);
- return CreateSerializer(serializerType);
+ return CreateTypeInfo(type, serializerType);
}
if (genericType == typeof(NullableKeyDictionary<,>))
{
Type serializerType =
typeof(NullableKeyDictionarySerializer<,>).MakeGenericType(genericArgs[0],
genericArgs[1]);
- return CreateSerializer(serializerType);
+ return CreateTypeInfo(type, serializerType);
}
}
throw new TypeNotRegisteredException($"No serializer available for
{type}");
}
- private Serializer? TryCreatePrimitiveCollectionSerializer(Type type)
+ private TypeInfo? TryCreatePrimitiveCollectionTypeInfo(Type type)
{
if (!type.IsGenericType)
{
@@ -1411,7 +1507,7 @@ public sealed class TypeResolver
: genericType == typeof(Queue<>)
?
typeof(PrimitiveQueueSerializer<,>).MakeGenericType(elementType, listLikeCodec)
:
typeof(PrimitiveStackSerializer<,>).MakeGenericType(elementType, listLikeCodec);
- return CreateSerializer(serializerType);
+ return CreateTypeInfo(type, serializerType);
}
if ((genericType == typeof(SortedSet<>) ||
@@ -1421,13 +1517,13 @@ public sealed class TypeResolver
Type serializerType = genericType == typeof(SortedSet<>)
?
typeof(PrimitiveSortedSetSerializer<,>).MakeGenericType(elementType, setCodec)
:
typeof(PrimitiveImmutableHashSetSerializer<,>).MakeGenericType(elementType,
setCodec);
- return CreateSerializer(serializerType);
+ return CreateTypeInfo(type, serializerType);
}
return null;
}
- private Serializer? TryCreatePrimitiveDictionarySerializer(Type type)
+ private TypeInfo? TryCreatePrimitiveDictionaryTypeInfo(Type type)
{
if (!type.IsGenericType)
{
@@ -1457,7 +1553,7 @@ public sealed class TypeResolver
: genericType == typeof(SortedList<,>)
?
typeof(PrimitiveStringKeySortedListSerializer<,>).MakeGenericType(valueType,
valueCodecType)
:
typeof(PrimitiveStringKeyConcurrentDictionarySerializer<,>).MakeGenericType(valueType,
valueCodecType);
- return CreateSerializer(serializerType);
+ return CreateTypeInfo(type, serializerType);
}
if (keyType == valueType &&
@@ -1470,38 +1566,80 @@ public sealed class TypeResolver
: genericType == typeof(SortedList<,>)
?
typeof(PrimitiveSameTypeSortedListSerializer<,>).MakeGenericType(valueType,
sameTypeCodec)
:
typeof(PrimitiveSameTypeConcurrentDictionarySerializer<,>).MakeGenericType(valueType,
sameTypeCodec);
- return CreateSerializer(serializerType);
+ return CreateTypeInfo(type, serializerType);
}
return null;
}
- private static Serializer CreateSerializer<TSerializer>()
- where TSerializer : Serializer, new()
+ private TypeInfo CreateTypeInfo(Type expectedType, Type serializerType)
{
- return new TSerializer();
+ object serializer;
+ try
+ {
+ serializer = Activator.CreateInstance(serializerType)
+ ?? throw new InvalidDataException($"failed to create
serializer for {serializerType}");
+ }
+ catch (Exception ex)
+ {
+ throw new InvalidDataException($"failed to create serializer for
{serializerType}: {ex.Message}");
+ }
+
+ return CreateTypeInfo(expectedType, serializer);
}
- private Serializer CreateSerializer(Type serializerType)
+ private static TypeInfo CreateTypeInfo(Type expectedType, object
serializer)
{
- if (!typeof(Serializer).IsAssignableFrom(serializerType))
+ Type? valueType = ResolveSerializerValueType(serializer.GetType());
+ if (valueType is null)
{
- throw new InvalidDataException($"{serializerType} is not a
serializer");
+ throw new InvalidDataException($"{serializer.GetType()} is not a
serializer");
}
- try
+ if (valueType != expectedType)
{
- if (Activator.CreateInstance(serializerType) is Serializer
serializer)
- {
- return serializer;
- }
+ throw new InvalidDataException($"serializer type mismatch for
{expectedType}, got {valueType}");
}
- catch (Exception ex)
+
+ MethodInfo createMethod =
CreateTypeInfoFromSerializerTypedMethod.MakeGenericMethod(valueType);
+ return (TypeInfo)createMethod.Invoke(null, [serializer])!;
+ }
+
+ private static TypeInfo CreateTypeInfoFromSerializerTyped<T>(object
serializerObject)
+ {
+ if (serializerObject is not Serializer<T> serializer)
{
- throw new InvalidDataException($"failed to create serializer for
{serializerType}: {ex.Message}");
+ throw new InvalidDataException($"serializer type mismatch for
{typeof(T)}");
+ }
+
+ return TypeInfo.Create(typeof(T), serializer);
+ }
+
+ private TypeInfo CreateNullableTypeInfo(Type valueType)
+ {
+ MethodInfo createMethod =
CreateNullableSerializerTypeInfoMethod.MakeGenericMethod(valueType);
+ return (TypeInfo)createMethod.Invoke(this, null)!;
+ }
+
+ private TypeInfo CreateNullableSerializerTypeInfo<T>() where T : struct
+ {
+ return TypeInfo.Create(typeof(T?), new NullableSerializer<T>());
+ }
+
+ private static Type? ResolveSerializerValueType(Type serializerType)
+ {
+ Type? current = serializerType;
+ while (current is not null)
+ {
+ if (current.IsGenericType && current.GetGenericTypeDefinition() ==
typeof(Serializer<>))
+ {
+ return current.GetGenericArguments()[0];
+ }
+
+ current = current.BaseType;
}
- throw new InvalidDataException($"{serializerType} is not a
serializer");
+ return null;
}
private static MetaString ReadMetaString(ByteReader reader,
MetaStringDecoder decoder, IReadOnlyList<MetaStringEncoding> encodings)
diff --git a/csharp/src/Fory/UnionSerializer.cs
b/csharp/src/Fory/UnionSerializer.cs
index 00a960317..90d4a1970 100644
--- a/csharp/src/Fory/UnionSerializer.cs
+++ b/csharp/src/Fory/UnionSerializer.cs
@@ -25,19 +25,11 @@ public sealed class UnionSerializer<TUnion> :
Serializer<TUnion>
{
private static readonly Func<int, object?, TUnion> Factory =
BuildFactory();
- public override TypeId StaticTypeId => TypeId.TypedUnion;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override TUnion DefaultValue => null!;
- public override bool IsNone(in TUnion value)
- {
- return value is null;
- }
-
public override void WriteData(WriteContext context, in TUnion value, bool
hasGenerics)
{
_ = hasGenerics;
diff --git a/csharp/tests/Fory.XlangPeer/Program.cs
b/csharp/tests/Fory.XlangPeer/Program.cs
index e0c6a1200..60fece54b 100644
--- a/csharp/tests/Fory.XlangPeer/Program.cs
+++ b/csharp/tests/Fory.XlangPeer/Program.cs
@@ -1027,11 +1027,7 @@ public sealed class MyExt
public sealed class MyExtSerializer : Serializer<MyExt>
{
- public override TypeId StaticTypeId => TypeId.Ext;
- public override bool IsNullableType => true;
- public override bool IsReferenceTrackableType => true;
public override MyExt DefaultValue => null!;
- public override bool IsNone(in MyExt value) => value is null;
public override void WriteData(WriteContext context, in MyExt value, bool
hasGenerics)
{
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]