I'm trying to migrate my code serializer from NetDataContract to Protobuf.Net.
Let's consider the following class example to help the understanding:
[DataContract(Name "a", IsReference = true)]
class Test
{
[DataMember(Name = "a")]
public int Id { get; set; }
[DataMember(Name = "b")]
public string Name { get; set; }
}
To be able to use Protobuf .NET using DataContract, I'm using the following options:
RuntimeTypeModel.Default.InferTagFromNameDefault = true;
RuntimeTypeModel.Default.AutoAddProtoContractTypesOnly = false;
Using those options, the serialization of the example showed above works, but when adding an inheritance of it, the complexity grows. Let's improve our example with this class:
[DataContract(Name = "b", IsReference = true)]
class InheritanceTest : Test
{
[DataMember(Name = "c")]
public string Text { get; set; }
}
Now, to be able to serialize the class "InheritanceTest" that inherits from "Test", I must add the ProtoInclude parameter (already tried to use only the KnownType but it didn't work). Class "Test" attributes should be like that:
[DataContract(Name "a", IsReference = true)]
[KnownType(typeof(InheritanceTest)]
[ProtoInclude(<TAG>, typeof(InheritanceTest)]
class Test { ... }
The complexity IMHO is when you have to fill the "TAG" with a number that is not automatically used from the members (DataMembers) auto-assigned order. In this example, if I use TAG=1 it gets error because property Id already uses it. The same with TAG=2 and property Name. So I need to put at least 3.
That's okay as this class is too simple, but what should I do when the class has several properties? And should I change the TAG whenever I add a property to it? Seems terrible for maintenance.
How can I do it in a simpler way? Am I missing something?
Considering it is automatically assigned, it should be done only once and cached. Even better, it should be done in compile time.
Additionally... why can't I use [KnownType] Attribute and the serializer auto-assigns the TAG based on the Name of the DataContract of the class type defined? Note that something similar happens with DataMember using the Name to auto-assign Order.
Yes, it does.
You should never change a tag. Ever.
Exactly.
It is, at runtime.
Well, I'm not focusing on the "infer" aspects, but in general that is an ongoing discussion I'm having with the compiler team.
I think so, yes; in particular, you should not be using "infer by name" options on models that are ever going to change. That option was added as a pragmatic way to just make things work on existing fixed models, but it is very brittle - and in many ways dangerous. There should be warnings that appear in your intellisense about this, but frankly the recommended option is: always be explicit. Add
[ProtoMember(42)]
(or whatever) to each property. Then there's no guessing, and no risk of adding new members that break things. You can see everything, and you can understand everything.