MessagePack-CSharp / MessagePack-CSharp

Extremely Fast MessagePack Serializer for C#(.NET, .NET Core, Unity, Xamarin). / msgpack.org[C#]
Other
5.73k stars 697 forks source link

Help request - using different (derived-)types for serialize/deserialize (IMessagePackFormatter<Tser, Tdes>)? #1778

Open GunSharp opened 8 months ago

GunSharp commented 8 months ago

Hi All,

I'm seeking assistance for a challenge I'm facing with an existing C# library that utilizes Microsoft binary serialization for a large number of classes. I'm exploring MessagePack as an alternative for serialization.

In this library, certain classes have a unique behavior during serialization and deserialization. During serialization, only an identifier is written into the stream, and during deserialization, this identifier is used to retrieve the corresponding object from a global dictionary.

However, I'm encountering difficulties when the deserialized object is of a different type than the serialized object. Let me illustrate this with a simplified class model:

class Base { readonly string Id = "MyId"; } class A : Base { }
class B : Base { }

(The goal is to substitute all references to instances of class A with references to instances of class B during deserialization. )

During serialization of class A , the identifier of the base class ("MyId") is written into the stream. To substitute class A with class B, an instance of class B is registered in the global dictionary with the identifier "MyId". Then, during deserialization from the stream, the deserialized object is retrieved from the global dictionary using the key "MyId" and is returned as deserialized object.

Currently, I'm using a CustomResolver based on SampleCustomResolver, where I've implemented logic to read and write the identifier. However, I'm struggling to achieve the desired behavior because IMessagePackFormatter requires the type for serialization and deserialization to be the same. Additionally, I'm facing challenges in making this work for the base class.

So maybe something like IMessagePackFormatter<A, B> where A : Base and B : Base

I'm also using TypelessContractlessStandardResolver to ensure compatibility with the old library and make as little changes as possible.

I would appreciate any tips or guidance on how to address this issue.

Thank you in advance for your assistance.

AArnott commented 8 months ago

I think you'll have to implement your formatter in terms of Base instead of A or B, since as you've noticed, there's no way an A formatter will be allowed to return a B. That will require that whatever node is pointing to your A/B objects actually declares the type to be Base instead of A simply for CLR type assignability rules.

GunSharp commented 7 months ago

Thank you mr AArnott for your reply.

I have tried to implement a formatter in terms of Base however I did not manage to make it work (my node indeed points to the base type). Somehow it doesn't seem to 'catch' my formatter when I use the formatterMap as shown in the examples.

    static readonly Dictionary<Type, object> formatterMap = new Dictionary<Type, object>()
    {
        {typeof(Base), new MyBaseFormatter ()},
        }

However, next week, I'll give it a try again.