[.net] Serializing Helper Class

Started by
6 comments, last by yaroslavd 18 years, 3 months ago
I was thinking of the best way to save things such as maps, characters, levels, etc. to disk. The obvious way to do it with C# is serialization. However, I see some problems with that. For example, what if I serialize a class instance, but then decide to add/remove a member? The serialized data becomes invalid. Also, what if we want to store a reference to a member instead of serializing it within the instance? For example, I don't want to store the 3d model of a character as part of the character save-file. Instead, I want to store it separately and just save the file name in the character save-file. These concerns led me to develop a Recorder class that fixes these shortcomings. Basically what it does is serialize members that are not recordable (don't implement the IRecordable interface) normally. If the member is IRecordable, it saves that member and then serializes its file path. If the member is an IRecordable array, it saves all the IRecordable's in the array and serializes a string[] of their file paths (this works for rectangular but not jagged arrays so far). For "loading" the instances, it reads in all the members. If there are any missing or there are extra ones (ie: members were added/deleted since serialization), an exception containing the problematic object and all its problematic members. These are left with the default type value (such as 0 or null), but the program can, of course, catch the exception and override this. So my question is whether you think that what I did is necessary and whether you see any problems with my approach. Thanks in advance.
Advertisement
With .NET 2.0 types with the [Serializable] attribute can have members added with version tolerant serialization. Additionally, if you don't want to serialize a member you can use the [NonSerialized] atrribute. So for the most part your approach seems unnecessary.
Quote:Original post by SiCrane
With .NET 2.0 types with the [Serializable] attribute can have members added with version tolerant serialization. Additionally, if you don't want to serialize a member you can use the [NonSerialized] atrribute. So for the most part your approach seems unnecessary.


Ah. Yes, I wrote the class way before 2.0. However, I looked up SerializableAttribute in MSDN, and I didn't find anything about versioning. In fact, in the Serialization Tut/FAQ, it says:

Quote:
The .NET Framework provides support for versioning and side-by-side execution, and all classes will work across versions if the interfaces of the classes remain the same. Because serialization deals with member variables and not interfaces, be cautious when adding member variables to, or removing them from, classes that will be serialized across versions. This is especially true for classes that do not implement the ISerializable interface. Any change of state of the current version, such as the addition of member variables, changing the types of variables, or changing their names, will mean that existing objects of the same type cannot be successfully deserialized if they were serialized with a previous version.

If the state of an object needs to change between versions, class authors have two choices:

Implement ISerializable. This allows you to take precise control of the serialization and deserialization process, allowing future state to be added and interpreted correctly during deserialization.
Mark nonessential member variables with the NonSerialized attribute. This option should only be used when you expect minor changes between different versions of a class. For example, when a new variable has been added to a later version of a class, the variable can be marked as NonSerialized to ensure the class remains compatible with previous versions.


So how exactly does versioning work with .NET 2.0 and what about the saving-by-reference issue that my code addresses? Thanks.

Edit: I found the new Serialization stuff on MSDN 2.0 and yes, the versioning is now part of it. However, the save-by-reference mechanism that I implemented still seems to be missing. Might I ask how people normally deal with this? Do most people use a custom file format and save the path to the resource (such as a 3d model or image), do they use custom serialization like me, maybe something different? Thank.

[Edited by - yaroslavd on December 29, 2005 10:39:24 PM]
Maybe you guys can tell me how YOU do it. I was thinking about using XML/datasets, but then you gotta read/write yourself as opposed to a serializer automatically doing it. And I'm still looking to see how you could save-by-reference with serialization (without customizing it, like I have). Thank you.
As the quoted help says: I implement ISerializable. This allows me to read and write my own serialization. One of the first things I serialize is a version number. Based upon this number I am able to read different sets (versions) of data during deserialization. Simple but effective.

Cheers
Thanks. Good to know someone else is doing it my way and that I'm not crazy for going through all that trouble. Of course now I should probably adapt my code to the changes in .NET 2.0.
I have a design question. Just like .NET 2.0, I made a SinceAttribute and even a DeprecatedSinceAttribute (so that deprecated members aren't uselessly recorded). However, I've been thinking about getting rid of this all-together. Instead, why not just deserialize all the members I can? If some members of the class are missing from the saved file, initialize them to 0/null and throw an exception (which will probably just be try/catch'd silently by the app, but can also be handled properly). If there are extra members that were saved by are not in the new class, leave them; they will just not be recorded on the next save, as they are not part of the class anymore. This is basically what my program does anyway, except I still label new members with [Since] (from my old design) and serialize/deserialize accordingly. The reason why I don't think I need [Since] anymore is because I don't need to deserialize different versions of a class, just update them. For example, if I add a new member to a class, I'm going to update all the previous saves by Save(Load(fileName)), so all files will be up-to-date and the class will never have to be able to read 5 different versions all with different members.

Does anyone see a design flaw with this? I know the above may be confusing, so please let me know if I should clarify something.
I just thought of a possible problem. I already implemented what happens when I have to record an array of IRecordable values, but what what if it's another type of collection? For example, List<SomeIRecordableType> ??? Actually, I think I know how to handle the latter case also, but I don't see how to handle something like, List<List<SomeIRecordableType>> because I can save the inside List, but how do I record a List of Lists?

How would you guys handle this?

This topic is closed to new replies.

Advertisement