angularsen / UnitsNet

Makes life working with units of measurement just a little bit better.
https://www.nuget.org/packages/UnitsNet/
MIT No Attribution
2.66k stars 382 forks source link

Protobuf-Net support not working because of DataMember order 0 #1356

Closed Brunni closed 9 months ago

Brunni commented 10 months ago

I tried transferring Quantities to a frontend via protobuf-net library. This library support DataContract and DataMember and therefore should easily work.

But: The entry 0 is not a valid proto entry. So it does not work.

Any ideas on how to get it working?

See also: https://stackoverflow.com/questions/1239295/stubborn-object-wont-serialize-with-protobuf-net

angularsen commented 10 months ago

Hi, sorry I have no experience with protobuf so I'm not sure what's wrong, but the link you posted seems relevant.

I see we declare [DataMember(Name = "Value", Order = 0)]

https://github.com/angularsen/UnitsNet/blob/70a6a2b7f1355ac02e5b441fa5c6b46ae012c266/CodeGen/Generators/UnitsNetGen/QuantityGenerator.cs#L82-L92

WCF example shows Order = 0, so this seems like a common use: https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/data-member-order#examples

WCF also has basic rules that say the Order is merely a grouping ID, and will sort alphabetically on members with same ID. So no problem starting on Order=1. Not sure if XML and other serializers differ from this though.

.NET docs say Order can be used, but no particular guidelines on what Order ID to start with: https://learn.microsoft.com/en-us/dotnet/api/system.runtime.serialization.datamemberattribute.order?view=net-8.0

In conclusion

I think we should be able to just change it to start with Order=1 and higher.

However, I believe this is a breaking change, in particular for serializers like protobuf that rely on ordering. I don't think many use it for that, but I guess we would still have to do a major version bump to change it.

WCF basic rules for data ordering

  1. If a data contract type is a part of an inheritance hierarchy, data members of its base types are always first in the order.
  2. Next in order are the current type’s data members that do not have the Order property of the DataMemberAttribute attribute set, in alphabetical order.
  3. Next are any data members that have the Order property of the DataMemberAttribute attribute set. These are ordered by the value of the Order property first and then alphabetically if there is more than one member of a certain Order value. Order values may be skipped.

Alphabetical order is established by calling the CompareOrdinal method.