views:

170

answers:

2

We released a program that serializes a very complex object using the .NET soap formatter. Soap didn't handle new versions of the classes involved very well so we're switching to the binary formatter.

To handle old object versions, I wrote a converter that deserializes the object in soap, and re-serializes it in binary.

The converter uses the versions of the classes at the time of the switch, so I put these classes in a different namespace to avoid clashes with the current versions.

Here's the problem: The namespace is apparently serialized with the class, so I get the error: Cannot cast NamespaceA.class as NamespaceB.class. (Arrgh!)

The classes are exactly the same; the only problem is the namespaces. How can I make the framework ignore the namespaces?

+2  A: 

According to this newsgroup posting, Changing a namespace causes errors when using "BinaryFormatter.Deserialize" to reload object data saved while defined under a different namesapce(sic), you should look at the SerializationBinder class.

However, I would urge you to find a different way of handling your data, as the binary formatter is meant to be used as a short-lived transport packaging handler, not a storage handler.

Have you looked at protocol buffers, as an example?


Edit: Ok, after reading your comment, and re-reading your question, it turns out your question has nothing to do with serialization after all, binary or otherwise.

The problem, apparently, is that you've serialized a class of type A, and try to deserialize it, or cast it after deserialization, to type B, a different type.

This will of course not work right out of the box, and can easily be reproduced without introducing serialization at all, you simply do this:

public class A { ... } <-- a class with some properties and stuff
public class B { ... } <-- another class, with the same properties and stuff

public void Test()
{
    A a = new A();
    B b = a;           <-- you get the same problem as in your code here
}

There are many ways to handle this. For instance, you can implement casting operators into one of the classes, which would make the above code work.

You can implement a "cloner" type method, one that takes an object of type A, constructs a new object of type B, and copies over all the properties and stuff.

Note that XML serialization uses the type you give to it as its root type, which means you can serialize an object of type A, and deserialize it as an object of type B, provided you only give B to the serialization object when you intend to deserialize, and providing that this type has enough meta-data to look like an object of type A.

I have a control question to you, which might give us some idea of why you're trying to do this: Why can't you deserialize it as the original type and leave it at that? Why do you have to cast it?

Lasse V. Karlsen
The problem is assigning the deserialized object (of NamespaceA) to a variable of the name class in NamespaceB. The deserialization appears to be successful, so a new binder wouldn't help here. Thanks anyway.
Deserializing into a variable of type Object works. The problem is getting it into a variable of the correct class so I can re-serialize it using the Binary formatter.It seems like I'd face this same problem with protocol buffers.
Lasse, I ended up doing something similar; a separate application using the same namespace, so there's no conflict.(Originally I wanted the converter in a DLL in the same application, and needed the different namespace to prevent clashes between the old/new versions of each class.)This turned out to be simpler that solutions which would require handling each class member separately (there are a lot of them).Thanks again for the suggestions.
A: 

You may find DataContractSerializer and XmlSerializer to be more forgiving. XmlSerializer is great for almost any XML format. DataContract has a few more limits (such as it doesn't play well with attributes) but should still work great for your scenario.

Matthew Whited