in rd-net/RdFramework.Reflection/ScalarSerializer.cs [96:189]
private SerializerPair CreateCustomScalar<T>(ISerializersSource serializers)
{
if (Mode.IsAssertion)
ReflectionSerializerVerifier.AssertValidScalar(typeof(T).GetTypeInfo());
TypeInfo typeInfo = typeof(T).GetTypeInfo();
var allowNullable = ReflectionSerializerVerifier.CanBeNull(typeInfo);
var memberInfos = SerializerReflectionUtil.GetSerializableFields(typeInfo);
var memberSetters = memberInfos.Select(ReflectionUtil.GetSetter).ToArray();
var memberGetters = memberInfos.Select(ReflectionUtil.GetGetter).ToArray();
// todo: consider using IL emit
CtxReadDelegate<object>[]? memberDeserializers = null;
CtxWriteDelegate<object>[]? memberSerializers = null;
CtxReadDelegate<T?> readerDelegate = (ctx, unsafeReader) =>
{
if (memberDeserializers == null)
using (new FirstChanceExceptionInterceptor.ThreadLocalDebugInfo(typeof(T)))
InitMemberSerializers();
Assertion.AssertNotNull(memberDeserializers);
if (allowNullable && !unsafeReader.ReadNullness())
return default;
object instance = FormatterServices.GetUninitializedObject(typeof(T));
try
{
for (var index = 0; index < memberDeserializers.Length; index++)
{
var memberValue = memberDeserializers[index](ctx, unsafeReader);
memberSetters[index](instance, memberValue);
}
}
catch (ArgumentException e)
{
e.Data["Type:" + typeof(T).ToString(true)] = "";
throw;
}
return (T) instance;
};
CtxWriteDelegate<T> writerDelegate = (ctx, unsafeWriter, value) =>
{
if (memberSerializers == null)
using (new FirstChanceExceptionInterceptor.ThreadLocalDebugInfo(typeof(T)))
InitMemberSerializers();
Assertion.AssertNotNull(memberSerializers);
if (allowNullable)
{
unsafeWriter.WriteBoolean(value != null);
if (value == null)
return;
}
try
{
for (var i = 0; i < memberSerializers.Length; i++)
{
var memberValue = memberGetters[i](value!);
memberSerializers[i](ctx, unsafeWriter, memberValue!);
}
}
catch (ArgumentException e)
{
e.Data["Type:" + typeof(T).ToString(true)] = "";
throw;
}
};
return new SerializerPair(readerDelegate, writerDelegate);
// Lazy resolve cyclic depencencies and give ability to serialize tree-like structures.
void InitMemberSerializers()
{
var read = new CtxReadDelegate<object>[memberInfos.Length];
var write = new CtxWriteDelegate<object>[memberInfos.Length];
for (var index = 0; index < memberInfos.Length; index++)
{
var mi = memberInfos[index];
var returnType = ReflectionUtil.GetReturnType(mi);
var serPair = serializers.GetOrRegisterSerializerPair(returnType, true);
read[index] = SerializerReflectionUtil.ConvertReader<object>(serPair.Reader);
write[index] = SerializerReflectionUtil.ConvertWriter<object>(serPair.Writer);
}
memberSerializers = write;
memberDeserializers = read;
}
}