Search code examples
.netxmlweb-servicesserializationxml-serialization

Circular reference error when serializing objects with custom Equals and GetHashCode methods


I get A circular reference was detected while serializing an object of type T error when returning my object as result of WebMethod of my asmx web service.

If I remove Equals and GetHashCode from class T problem disappears. I don't have any circular references, so it looks like serialization detects circular references by comparing objects and if they are equal it thinks that there are circles.

Of course, I could define one class with Equals and another class for serialization, like many people do, and then copy data from one into another, but I want to be able to do it in one class to avoid parallel class hierarchies as one of code smells.

I want to be able to define Equals, GetHashCode and keep it Serializable. How ?


Solution

  • One way to do it is to inherit every class involved in serialization from one interface, which defines OnSerializing method and implement that method in every class to invoke it for eligible children. Also have Serializing private bool member in every class with false as default and set it to true inside OnSerializing. That will allow to call it on root and propagate to all serializable nodes till every leaf.

    Call returnValue.OnSerializing() right before returning serialiable returnValue from WebMethod.

    Every time you override Equals first line should be if(Serializing)return base.Equals(obj);, first line in GetHashCode should be if(Serializing)return base.GetHashCode();

    That way right before returning from WebMethod by calling OnSerializing you mark whole tree to disable customization of Equals and GetHashCode.

    If you need to do something after serialization (for example to save on disk and then return), then define OnSerialized and propagate through tree same way to set Serializing flag to false.

    Of course, if possible, just inherit all serializable objects from one class instead of interface and implement everything there to reduce implementation overhead in every serializable class.