Reputation: 4151
I am storing a serialized object as json (or perhaps xml in the future) in a database. At some later point this object will be pulled and derserialized. The base class is HighChart but there are several derived types as well such as HighChart.ColumnBarChart. The type of the chart is stored in the JSON. The problem is I cant figure out how I'm going to dynamically select the class to deserialize as.
My solution needs to provide a way to automatically take into account future derived types (I'm going to be expanding the number of chart types and do not want to program something new for every chart type).
I know that I could store the type to a seperate DB field - but again I would have to use a switch statement in my Deserialize method for every type. I could also parse the json string and discover the chart type, but again - I would have to use a switch statement for every possible type.
Thanks for your thoughts!
Upvotes: 2
Views: 2612
Reputation: 34325
You mention that you cannot easily cast from a base type to a derived type. Why is that? I was able to do so. My Dog entity has a property (DogYears) that doesn't exist in the Animal base type, yet I can still deserialize Dog as Animal and then cast it and display DogYears.
public class Dog : Animal
{
public int DogYears { get; set; } // This doesn't exist in the base class
public Dog()
{
this.DogYears = 4;
}
}
Here, we serialize Dog as the base type, then deserialize as the base type, and yet we can still display the dog-specific property:
private static void JsonSerialization()
{
Animal dog = new Dog();
var stream = new MemoryStream();
var serializer = new DataContractJsonSerializer(typeof(Animal));
serializer.WriteObject(stream, dog);
stream.Position = 0;
Animal deserializedDog = serializer.ReadObject(stream) as Animal;
Console.WriteLine(((Dog)deserializedDog).DogYears);
}
The console properly displays "4".
For completeness, here is the Animal class:
[KnownType(typeof(Dog))]
public abstract class Animal
{
// Properties here
}
Upvotes: 2
Reputation: 13097
If you store the Assembly Qualified Name of the new type in the database, you'll be able to use that to instantiate an instance of the type without changing the type loading code. The implementation looks like this:
string assemblyQualifiedName = getAssemblyQualifiedNameFromDatabase();
var futureType = Type.GetType(assemblyQualifiedName);
var serializer = new DataContractJsonSerializer(futureType);
var result = (HighChart)serializer.ReadObject(stream);
Note that there are no case statements: it is not necessary to know the actual type in advance. However, this code assumes that you have included the new type, either directly in the project or by reference. If you want to dynamically load new types using an assembly that hasn't been recompiled with a reference to the new type, then you'll have to load the assembly that contains the new type and use a reference to the loaded assembly in order to create the type reference.
Upvotes: 3