views:

335

answers:

3

I have a library (written in C#) for which I need to read/write representations of my objects to disk (or to any Stream) in a particular binary format (to ensure compatibility with C/Java library implementations). The format requires a fair amount of bit-packing and some DEFLATE'd bytestreams. I would like my library, however, to be as idiomatic .NET as possible, however, and so would like to provide an API as close as possible to the normal binary serialization process. I'm aware of the ability to implement the IFormatter interface, but being that I really am unable to reuse any part of the built-in serialization stack, is it worth doing this, or will it just bring unnecessary overhead. In other words:

Implement IFormatter and co.

OR

Just provide "Serialize"/"Deserialize" methods that act on a Stream?


A good point brought up below about needing the serialization semantics for any case involving Remoting. In a case where using MarshalByRef objects is feasible, I'm pretty sure that this won't be an issue, so leaving that aside are there any benefits or drawbacks to using the ISerializable/IFormatter versus a custom stack (or, is my understanding remoting incorrectly)?

A: 

I have always gone with the latter. There isn't much use in reusing the serialization framework if all you're doing is writing a file to a specific framework. The only place I've run into any issues with using a custom serialization framework is when remoting, you have to make your objects serializable.

This may not help you since you have to write to a specific format, but protobuf and sqlite are good tools for doing custom serialization.

Michael Hedgpeth
Thanks for the pointer - I'm actually hoping to offer protobuf serialization as a possible extension, but the default needs to be in this compatible format.
Matt Enright
A: 

I'd do the former. There's not much to the interface, and so if you're mimicking the structure anyway adding an ": IFormatter" and the other code necessary to get full compatibility won't take much.

Joel Coehoorn
If I'm not using the built-in formatters, what specific things do I need to look for that are going to be executed outside of my custom formatter? (I'm concerned about adding extra overhead from the full Serialization stack if I'm not using it, not so much about the overhead of writing the code).
Matt Enright
A bigger question is what _won't_ be executed: potentially your type's constructor and property setters.
Joel Coehoorn
A: 

Writing your own serialization code is error prone and time consuming.

As a thought - have you considered existing open-source portable formats, for example "protocol buffers"? This is a high density binary serialization format that underpins much of Google's data transfer etc. Versions are available in a wide range of languages - including Java/C++ etc (in the core Google distribution), and a vast range of others.

In particular, for .NET-idiomatic usage, protobuf-net looks a lot like XmlSerializer or DataContractSerializer (indeed, it can even work purely with xml/wcf attributes if it includes an order on each element) - or can use the specific protobuf-net attributes:

[ProtoContract]
class Person {
    [ProtoMember(1)]
    public string Name {get;set;}
}

If you want to guarantee portability to other implementations, the recommendation is to start "contract first", with a ".proto" file - in this case, something like:

message person {
    required string name = 1;
}

This .proto file can then be used to generate any language-specific variant; so with protobuf-net you'd run it through "protogen" (included in protobuf-net; and a VS2008 add-on is in progress); or for Java/C++ etc you'd run it through "protoc" (included in Google's protobuf). "protogen" in protobuf-net can currently emit C# and VB, but it is pretty easy to add another language if you want to use F# etc - it just involves writing (or migrating) an xslt.

There is also another .NET version that is a more direct port of the Java version; as such it is less .NET idiomatic. This is dotnet-protobufs.

Marc Gravell
Yes, I'm aware of protocoll buffers, and Thrift, and sqlite, and everything else that is being suggested - and for compatibility I need to be using the binary format dictated by other implementations. I actually have looked at your (protobuf-net) sources to see how you implemented the serialization; but for this particular case I am definitely writing the binary read/write methods anyways. My question is if it is worth inheriting IFormatter and friends to do so, or just to do it 'outside' the framework as such.
Matt Enright