Search code examples
c#serializationmsgpack

"is not registered in resolver" exception when serializing with abstract class using MessagePack


Trying to serialize componentMappers . The Exception is throwed at .Serialize():

var componentMappers = new Bag<ComponentMapper>();
var componentMappersS = MessagePackSerializer.Serialize(componentMappers);
var componentMappersD = MessagePackSerializer.Deserialize<Bag<ComponentMapper>>(componentMappersS);
FormatterNotRegisteredException: MonoGame.Extended.Entities.ComponentMapper is not registered in resolver: MessagePack.Resolvers.StandardResolver

[MessagePackObject]
    public abstract class ComponentMapper
    {
        [SerializationConstructor]
        protected ComponentMapper(int id, Type componentType)
        {
            Id = id;
            ComponentType = componentType;
        }

        [Key(0)]
        public int Id { get; set; }
        [Key(2)]
        public Type ComponentType { get; }
        public abstract bool Has(int entityId);
        public abstract void Delete(int entityId);
    }

    [MessagePackObject]
    public class ComponentMapper<T> : ComponentMapper
        where T : class
    {
        private readonly Action<int> _onCompositionChanged;
        
        // Custom
        [SerializationConstructor]
        public ComponentMapper(int id, Bag<T> components) : base(id, typeof(T))
        {
            Id = id;
            Components = components;
        }
    }
public class Bag<T> : IEnumerable<T>
    {
        [Key(0)]
        public T[] _items;
        [Key(1)]
        public bool _isPrimitive;

        [IgnoreMember]
        public int Capacity => _items.Length;
        [IgnoreMember]
        public bool IsEmpty => Count == 0;
        [IgnoreMember]
        public int Count { get; private set; }

        // Custom
        [SerializationConstructor]
        public Bag(T[] _items, bool _isPrimitive)
        {
            this._isPrimitive = _isPrimitive;
            this._items = _items;
        }
}

Though if serializing for a specific type, i.e.:

var componentMapper = new ComponentMapper<Human>(0, new Bag<Human>());
            var componentMapperS = MessagePackSerializer.Serialize(componentMapper);
            var componentMapperD = MessagePackSerializer.Deserialize<ComponentMapper<Human>>(componentMapperS);

there are no problems.


Solution

  • This happens because ComponentMapper is abstract so I have to use MessagePacks Union. MessagePack tried to serialize the abstract class but it didn't know what type is exactly "underneath it" so you have to mark possible candidates with Union.