I would go with the third option (objects!), But with a slight twist.
Point: you have a set of objects with a specific scheme ...
public class Animal { public string Name { get; set; } // user-readable public double Weight { get; set; } public Habitat Habitat { get; set; } public void Swim(); }
but you want them to be predetermined. Trick: If you serialize such an object, you do not want its fields to be serialized . Field initialization is the responsibility of the application, and the only thing you really want in your serialized version is the "type" of the animal. This will allow you to change Otter to Sea Otter and keep the data consistent.
Therefore, you need some idea of the "type of animal" - and this is the only thing you want to serialize. . When deserializing, you want to read the type identifier and initialize all fields based on it.
Oh, and another attempt at deserialization, you don’t want to create a new object! You want to read the ID (and only the ID) and get one of the predefined objects (corresponding to this ID).
The code might look like this:
public class Animal { public static Animal Otter; public static Animal Narwhal;
So far so good. If there are dependencies that prevent you from making static instances, you can add lazy initialization to all Animal objects.
The Animal class begins to look like a "pair of loners in one place."
Now how to connect it to the .NET serialization engine (BinarySerializer or DataContractSerializer). We want the serializer to use GetAnimalById instead of the constructor when deserializing and to keep only the identifier when serializing.
Depending on your serialization API, you can do this using ISerializationSurrogate or IDataContractSurrogate. This is an example:
class Surrogate : IDataContractSurrogate { public Type GetDataContractType(Type type) { if (typeof(Animal).IsAssignableFrom(type)) return typeof(int); return type; } public object GetObjectToSerialize(object obj, Type targetType) {
BTW: DataContacts seems to have an error (or is it a function?) That makes them act weird when the lookup type is the base type. I had such a problem when serializing objective objects like strings - the GetDeserializedObject method never started when deserializing. If you encounter this behavior, use a wrapper class or structure around this single int field in the surrogate.