2

Our client/server app uses a NetDataContractSerializer to serialize arbitrary Serializable objects.

The output of BinaryFormatter would be somewhat smaller, performance however isn't really better.

Now smaller representations are possible (e.g. the outputs of XmlSerializer and DataContractSerializer, Json, Protocol Buffers, Thrift, etc.), that also happen to serialize and deserialize much faster.

However, in order to use those I'd have to go to every single one of the Serializable classes and add attributes and potentially change access levels of fields etc. Not only are these classes spread over many different internal projects, but our clients have their own dlls with Serializable classes which would have to be modified. In other words, a major undertaking.

Is there any other performance improvement, and potential size reduction (other than gzipping etc.), possible for Serializable objects?

Evgeniy Berezovsky
  • 18,571
  • 13
  • 82
  • 156

2 Answers2

0

Many of those serializers do not require custom attributes - in fact some are specifically designed to recognize and work with SerializableAttribute. See, for example:

Json.NET example:

var settings = new JsonSerializerSettings
{ 
    TypeNameHandling = TypeNameHandling.All,
    PreserveReferencesHandling = PreserveReferencesHandling.Objects,
};
string serialized = JsonConvert.SerializeObject(obj, settings);
var deserialized = JsonConvert.DeserializeObject(serialized, settings);

UPDATE: You don't need to fork Json.NET to do the type instantiation. I'm using a custom JsonConverter as described in this article.

Lars Kemmann
  • 5,509
  • 3
  • 35
  • 67
  • Quoting from your protobuf link: `Contract types Protobuf-net expects contract types to be explicitly marked as such; types can be marked [ProtoContract], [DataContract] or [XmlType] for this purpose ([Serializable] is not required and is not used)` – Evgeniy Berezovsky Aug 13 '14 at 04:57
  • That's what I said. Quoting also from the very first line of that protobuf project wiki page: "Note that in v2 everything can also be configured at runtime without needing to edit any types." – Lars Kemmann Aug 13 '14 at 04:59
  • I could get Json.NET to work (and added an example to your answer), but in case of protobuf-net I a) seem to have to add every (non-protobuf-annotated) type manually before serializing b) specify the exact type when deserializing (not e.g. a common super interface/class) c) protobuf complains unless there is a parameterless constructor. I.e. it doesn't seem to work as a drop-in replacement for BinaryFormatter/NetDataContractSerializer. – Evgeniy Berezovsky Aug 13 '14 at 05:50
  • Thanks for adding that. Yes, there are definitely limitations on what's possible. If you're looking for a drop-in replacement that performs better and doesn't have any significant change in behavior, I don't think you'll find one - there's a reason the performance engineers at Microsoft get paid well. :) I would say it's definitely worth considering the benefits of adding a `[DataContract]` annotation, because as I said `[Serializable]` is really not meant for wire transmission unless you're sure you want to tightly couple your client & server. `[DataContract]` will open up more options. – Lars Kemmann Aug 13 '14 at 16:39
  • Well, I'm not sure `NetDataContractSerializer` and `Json.NET` are 100% equiv, but the former takes 1.5 times the time of the latter in tests with actual complicated nested objects that I did, which surprised me a bit, as MS can do a lot of 'unsafe' stuff internally that Json.NET cannot. – Evgeniy Berezovsky Aug 13 '14 at 23:30
  • The Json.NET snippet is still not enough to make it serialize like `NetDataContractSerializer`. Depending on the constructor setup of your class, you'll run into `Unable to find a constructor to use for type 'xxx'. A class should either have a default constructor, one constructor with arguments or a constructor marked with the JsonConstructor attribute`, which can be fixed by either changing your class (something I'm trying to avoid as I'm not controlling all classes) or by [forking Json.NET](http://blog.halan.se/post/Deserializing-objects-with-non-default-constructors-in-JSON-NET.aspx). – Evgeniy Berezovsky Aug 15 '14 at 04:25
0

My conclusion after checking out Lars Kemmann's suggestions: There is no alternative to NetDataContractSerializer/BinaryFormatter that serializes and deserializes the in the same way.

I played around with Json.NET, and it kind of works, but as is often the case, the devil is in the details (see also my comments to Lars' answer):

Testing with real life objects it turned out my deserialized objects aren't 100% equivalent to the original ones, stemming from fields in super classes that don't get serialized. At least that is what it seems after a cursory check.

Protobuf-net is not an option either, as you

  1. have to register every (non-protobuf-annotated) type manually before serializing
  2. have to specify the exact type when deserializing
  3. it complains about classes that don't have a parameterless constructor
Evgeniy Berezovsky
  • 18,571
  • 13
  • 82
  • 156