C# Xml serialization of objects with IEnumerable - c#

whenever I try to serialize an object that has an IEnumerable collection I get a big dirty error telling me it can't serialize it because it's an interface. Now I get why it's happening but it raises some other questions for me. Like if I intend on having collections within my objects AND I want to serialize them do I need to resort to
Using List<>, CollectionBase, ReadOnlyCollectionBase in my objects.
Making my objects implement the IXmlSerializable interface.
Decorating my classes with horrible attributes.
Writing my own serializer.
What is the best practice way to go?

Speaking as a serializer author, I know exactly why it gets very hard to robustly work just from IEnumerable<T>, especially for "get-only" properties. You might try IList<T> (although it wouldn't amaze me if it wants a concrete type such as List<T>/T[]), but I suspect the real problem here is that you trying to use one model to do two things, and are unhappy at having to compromise to do it.
Fine: if you don't want to compromise your domain model, write a separate DTO model that is used for serialization, and just map between them. This is usually trivial, and will allow the serializer and the domain model to each excel at their one job. It will also help immensely when you need to "version" the system or introduce a different serializer (JSON, protobuf, etc).
Re your bullets:
I suspect any concrete list type (even your own) with Add etc will work
I don't recommend that to anyone - it is painful to do reliably
nothing ugly about attributes; again, I suspect your complaint is about attributing your domain model - so: fine, don't do that - have a separate model; you can actually do all this at runtime, but it is much more work (see XmlAttributeOverrides, but watch out for leaking assemblies if you do this)
don't underestimate how much work that is; the basics - seductively easy; but the non-trivial scenarios can be brutal

For use interface or derivade classes you MUST use the XmlSerializer(Type type, Type[] extraTypes) constructor.
In extraTypes you MUST include all possible classes which can implement the interfaces in your classes.

Related

Serialize custom external class that is not serializable

I wonder if there is any possibility of serializing a class described in a topic.
Suppose we have someone's library that is shared as binary DLL file. Additionally a creator of this lib created a class that is not Serializable. How to serialize such a class? I know I can create a twin-class that contains all the poperties etc. that can be serialized. But is there any other, easier solution to do this? How do you serialize classes that are "not yours" and are stored as binary only?
The 3rd party class is an implementation detail; frankly, it is a very bad idea to involve this in your serialization, as you are then completely fenced into a corner, and can never change implementation. You would also face significant risk of versioning issues - something that BinaryFormatter simply doesn't handle well.
It might not be what you want to hear, but I offer two recommendations:
do not serialize implementation details; serialize the data (only); this may indeed require you to write a DTO that mirrors the implementation, but this is usually a trivial job
make sure you understand the implications of BinaryFormatter; frankly, I never recommend it - it has... glitches.
As for workarounds: you can investigate serialization surrogates, but that isn't a trivial thing to do inside BinaryFormatter, and is basically just a re-statement of the first bullet.
If it was me (although I am hugely biased), I would change serializer; protobuf-net (disclosure: I'm the author) works as a binary serializer, and has easy-to-implement support for surrogates if the third-party model is already coupled to your model.

c#: make a 3rd party object serializable

On my own object I can add the metatag [Serializable] to make it serializable. Now I use a 3rd party library that I need to be serializable. I inspected the code and it should not be a problem. Is there a way to fix this without altering the 3rd party code?
My advice would be: serialize data, not implementation. The fact of the existence of a 3rd-party object is nothing to do with the data; that is an implementation detail. As such, I always offer the same advice: if serialization ever gets complex, the first thing to do is to introduce a separate DTO model that represents the data in isolation of the implementation, and just map the current state to that DTO. This allows you to handle implementation changes without impact on the storage, and allows otherwise non-serializable objects to be serialized.
Some serializers offer workarounds - for example with protobuf-net you can a: supply the serialization information for any type at runtime, and b: supply a "surrogate" to use automatically when it gets tricky, but - using a DTO model is simpler and easier to maintain.
Your use of [Serializable] suggests BinaryFormatter; in my opinion, this is almost never a good choice for any kind of storage, since BinaryFormatter relies on implementation details. It works nicely for passing data between two in-sync app-domains, though
If the types are public you should be able to use the XmlSerializer to do what you want.
There's more information on this here
Serializes and deserializes objects into and from XML documents. The
XmlSerializer enables you to control how objects are encoded into XML.
Exactly take your subclass and make it serializable.
[Serializable] public class Foo: Bar {}
Write an adapter or be prepared to do something more extreme like disassembling the assembly, injecting the serializable attribute and reassembling.

Can DTO have basic object level operations like Clone?

I understand DTO's strict definition is to serve as container to transport data, it shouldn't have any behavior. However, I have faced a situation with a need to clone the DTO, two options:
1. create a Clone method (ICloneable?) in DTO
2. create generic utility class to clone DTO
I currently use option #2. However, I think #1 is acceptable provided there are no logic in DTO. I would like see if any of you faced a similar situation with DTO that required basic operations like Clone, ToString, especially DTOs that had inheritance. Thanks.
If it is a DTO, it should be designed for serialization - in which case your best option is to serialize it via whatever process it is designed, and rehydrate a clone from there. It is pretty rare that this would be a performance issue.
Clone is an operation that is not very commonly needed. However, should you truly need to clone objects it's perfectly acceptable to implement it directly on the object. This will allow you to access the protected MemberwiseClone feature in relation to ICloneable
Cloning is frequently implemented with MemberwiseClone. See Cannot access protected member 'object.MemberwiseClone()' .
If you need deep graph cloning, look into the BinaryFormatter to clone your object. Or look into changing your model to not expect cloning.

Why should I not make a class Serializable?

I'm storing some objects in my viewstate and I was wondering if there are any disadvantages to making a class Serializable?
Is it bad practice to make all of the classes Serializable?
Firstly. Avoid viewstate.
Generally serialization (textual) is used for transferring objects.
You should avoid marking any class as serializable that is not a DTO (Data transfer object) or message class. We do this for several reasons. What ever picks up your class in serialized format may not have the method information (which is in the original assembly) of a non DTO class. Secondly, a class may reference a resource (DB connection, file handle, etc) Do NOT serialize these, since de serialization does not re-establish resource connections and state, unless explicitly designed for, but is still a bad idea.
So in summary: Do NOT serialize when you have contextual methods and storing data for a thrid party to use. (Like a service response with methods is a bad idea). And do NOT serialize when the class contains a resource reference. Keep your serializable object clean from methods as much as possible. This might involve a little re factoring into a service type pattern.
Do serialize DTO's and messages.
This is more of a design choice.
It is a good practice to make all classes that are actually Serializable as Serializable. I would just use common sense, and set it for those classes that are intended for crossing process boundaries (DTO classes).
So it those classes which:
All their properties are simple types
And if they have complex properties, their types themselves are serializable
Marking it as [Serializable] (or ISerializable) is necessary for anything using BinaryFormatter, which may well include viewstate under the default configuration. As for good vs bad practice... well, most classes don't need to be serialized, and IMO even when they are, using BinaryFormatter is not always the best choice*. And specifically, marking it as both [Serializable] and [DataContract] will cause an exception IIRC.
*=actually, IMO BinaryFormatter is very rarely a good choice, but I might be biased... and I deliberately don't use viewstate ;p

Custom serializer and inheritence in C#

I'm learning about serialization in C# and I have the basics down, but now I am trying something a little more complicated and I'm looking for some pointers on best practice (I can achieve what I want, I just want to know the 'right'/easiest/least code/most robust method of doing it).
I have a racing track which is made up of sections. Each section type inherits from a common TrackSection class. The TrackSection class holds a lot of data on geometry and other things that I don't want to save out and it needs some context information when the constructor is called, so I have implemented the ISerializable interface and provided my own methods to handle (de)serialization. The classes that inherit from TrackSection are a lot simpler, and I would be happy for all their fields to be serialized automatically, but I assume that since the base class is ISerializable they probably need to do it manually as well (I have added the deserialization constructor and call the base class's deserialization constructor in each). When it comes to serializing though I'm not sure what to do, I would have expected ISerializable's GetObjectData() method to be virtual so I could extend the serialization in sub-classes. Do I simply need to implement my own virtual method that is called from the base class's GetObjectData(), or am I going about this all wrong?
As I say, I have it working but any better solution or any general tips about what I'm doing would be much appreciated, as I can't help but feel my solution is a little more complicated than it needs to be. Thanks.
Unless you're doing something where you need to implement ISerializable, you could, instead just mark the class with the Serializable attribute and mark the fields that you don't want serialized as NonSerialized

Categories