in rd-net/RdFramework.Reflection/ReflectionSerializers.cs [184:274]
private void RegisterModelSerializer<T>()
{
if (Mode.IsAssertion) Assertion.Assert(!ReflectionSerializerVerifier.IsScalar(typeof(T)), "Type {0} should be either RdModel or RdExt.", typeof(T));
var typeInfo = typeof(T).GetTypeInfo();
ReflectionSerializerVerifier.AssertRoot(typeInfo);
var isScalar = ReflectionSerializerVerifier.IsScalar(typeInfo);
bool allowNullable = ReflectionSerializerVerifier.HasRdModelAttribute(typeInfo) || (isScalar && ReflectionSerializerVerifier.CanBeNull(typeInfo));
/* var builtInSerializer = TryGetBuiltInSerializer(typeInfo);
if (builtInSerializer != null)
{
myStaticSerializers[typeof(T)] = builtInSerializer;
return;
}*/
var memberInfos = SerializerReflectionUtil.GetSerializableFields(typeInfo);
var memberSetters = memberInfos.Select(ReflectionUtil.GetSetter).ToArray();
var memberGetters = memberInfos.Select(ReflectionUtil.GetGetter).ToArray();
// todo: consider using IL emit
var memberDeserializers = new CtxReadDelegate<object>[memberInfos.Length];
var memberSerializers = new CtxWriteDelegate<object?>[memberInfos.Length];
for (var index = 0; index < memberInfos.Length; index++)
{
var mi = memberInfos[index];
var returnType = ReflectionUtil.GetReturnType(mi);
var serPair = GetOrRegisterSerializerPair(returnType);
memberDeserializers[index] = SerializerReflectionUtil.ConvertReader<object>(serPair.Reader);
memberSerializers[index] = SerializerReflectionUtil.ConvertWriter<object?>(serPair.Writer);
}
var type = typeInfo.AsType();
CtxReadDelegate<T?> readerDelegate = (ctx, unsafeReader) =>
{
if (allowNullable && !unsafeReader.ReadNullness())
return default;
object instance;
if (isScalar)
{
instance = FormatterServices.GetUninitializedObject(type);
}
else
{
instance = Activator.CreateInstance(type);
}
var bindableInstance = instance as IRdBindable;
RdId id = default(RdId);
if (bindableInstance != null)
id = unsafeReader.ReadRdId();
for (var index = 0; index < memberDeserializers.Length; index++)
{
var value = memberDeserializers[index](ctx, unsafeReader);
memberSetters[index](instance, value);
}
bindableInstance?.WithId(id);
return (T)instance;
};
CtxWriteDelegate<T?> writerDelegate = (ctx, unsafeWriter, value) =>
{
if (allowNullable)
{
unsafeWriter.WriteBoolean(value != null);
if (value == null)
return;
}
if (value == null)
Assertion.Fail("Type {0} isn't expected to be null", typeof(T));
if (value is IRdBindable bindableInstance)
{
unsafeWriter.Write(bindableInstance.RdId);
}
for (var i = 0; i < memberDeserializers.Length; i++)
{
var memberValue = memberGetters[i](value);
memberSerializers[i](ctx, unsafeWriter, memberValue);
}
};
myStaticSerializers[type] = new SerializerPair(readerDelegate, writerDelegate);
}