views:

63

answers:

4

In my project I have a class which I Serialize in Binary format to the disk.

Due to some new requirement I need to create a new class which is derived from the original class.

eg

[Serializable]
public class Sample
{
    String someString;
    int someInt;

    public Sample()
    {
    }

    public Sample(String _someString, int _someInt)
    {
        this.someInt = _someInt;
        this.someString = _someString;
    }

    public String SomeString
    {
        get { return someString; }
    }

    public int SomeInt
    {
        get { return someInt; }
    }
}

[Serializable]
public class DerivedSample : Sample
{
    String someMoreString;
    int someMoreInt;

    public DerivedSample ()
        : base()
    {
    }

    public DerivedSample (String _someString, int _someInt, String _someMoreString, int _someMoreInt)
        :
        base(_someString, _someInt)
    {
        this.someMoreString = _someMoreString;
        this.someMoreInt = _someMoreInt;
    }
    public String SomeMoreString
    {
        get { return someMoreString; }
    }

    public int SomeMoreInt
    {
        get { return someMoreInt; }
    }
}

When I try to De serialize an old file which contains only object of Sample it works fine, in the current assembly. That means backward compatibility is there. But when I try to deserialize the file which contains object of DerivedSample using the previous version of the assembly application crashes. Which means forward compatibilty needs to be taken care off...

It it possible to say read only the base class part of the object from new version of the file?

A: 

It it possible to say read only the base class part of the object from new version of the file?

In that case it would probably be better to deserialize the object as Sample, and then provide a constructor in DerivedSample that copies the necessary attributes. That way you maintain backward compatibility with previous objects, but can still use your newer classes.

On a side note, WCF serialization has handled a lot of object versioning problems. You may consider switching to use DataContracts for your serialization if your project requires backward/forward compatibility with object versioning.

-Doug

Doug
Hi Doug, like I said fwd compatibilty was not a problem, because while de-serializing the file, I was using the reference of base class. So if a file contains object of Sample it will be de-serialize normally. And if it contains DerivedSample obj, it still get deserialized normally, Will have to typecast it to DerivedSample if I need to access the new properties. Any ways thanx for the reply.
Anand
A: 

It seems from the question that what's failing is the attempt to read a serialized DerivedSample into an application that has the old version of the assembly -- thus there is no DerivedSample class, only the Sample class.

I don't think this is intended to work, since the class that was serialized (DerivedSample) simply doesn't exist in any form in the deserializing application.

Serialization seems to work best when the class itself is versioned rather than using inheritance. So you would modify Sample to add the new properties, rather than deriving from it. The new fields should be marked as optional (providing backward compatibility) and extraneous fields are ignored in deserialization into an older version (providing forward compatibility): http://msdn.microsoft.com/en-us/library/ms229752(VS.80).aspx

Is that an option for you?

Ragoczy
Actually no, because now we have two different type of files sample type and DerivedSample type. We need to handle both of them indiviually. But may be I will use Optional fields and enums to maintian the type.
Anand
Any way thanks for the reply
Anand
+1  A: 

Is this new work or existing work? BinaryFormatter is very touchy about things like this, but if you want binary output you might want to consider something like protobuf-net, which uses more predictable contracts-based output; meaning you can get the data back into your app no matter if you change the specific types.

If binary isn't important you might also consider xml; XmlSerializer, DataContractSerializer, etc. IMO, BinaryFormatter should not be used to persist data for anything other than the shortest time.

You stress that forward / backward compatibility is important; in that case I strongly urge you that BinaryFormatter can bite hard with this.

Marc Gravell
Thanks bro... But very unfortunately, I was forced to use BinaryFormatter, because the third party dll I was using needed binary input. A byte array to be specific. Now I will have to live with it, and will have to convince the boss that backword compatibility is achived, forward compatibility cannot be done. Best solution I can offer is, application will exit gracefully!!
Anand
@Anand - binary is no problem; protobuf-net is a binary serializer; it just isn't `BinaryFormatter` ;-p Of course that doesn't help if it is already too late. Next time, maybe. Fundamentally, *all* serializers can be treated as binary. And most can (one way or another) be treated as text.
Marc Gravell
A: 

You need to use so called serialization surrogate. You can inject it into binary serializer and then at runtime the surrogate is able to substitute what is being serialized/deserialized for your own type. I used it in the past when the type has been moved between assemblies and the code was no longer able to deserialize old files. More on the surrogates here: http://msdn.microsoft.com/en-us/library/system.runtime.serialization.surrogateselector(v=VS.100).aspx

Marcin Kaluza