private void RegisterModelSerializer()

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);
  }