2

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!

Wjdavis5
  • 3,952
  • 7
  • 35
  • 63
  • I don't think you have to deserialize it as the concrete type. Can't you just deserialize it as the base type, then use it as the concrete type (cast it) where you need to? – Bob Horn Jul 13 '13 at 01:27
  • @BobHorn I can easily cast from a derived type to a base type, but I cannot easily cast from a base type to a derived type (Derived types typically have more functionality then base types) Also on this topic is this : http://stackoverflow.com/a/124347/1387186 – Wjdavis5 Jul 13 '13 at 01:42
  • When you cast to a base type, you don't lose information. It's still there. You're only *using* it as the base type. If you cast to the derived type, you'll have access to the derived properties. – Bob Horn Jul 13 '13 at 14:02

2 Answers2

3

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.

Paul Keister
  • 12,851
  • 5
  • 46
  • 75
2

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
}
Bob Horn
  • 33,387
  • 34
  • 113
  • 219