3x071c
3x071c

Reputation: 1016

C# Deserializing JSON to class dependent on a type property

Let's say I have this little json snippet:

{
  "Type": "Bar",
  "BarOnly": "This is a string readable when deserialized to the Bar class only, as declared in my type key"
}

I also have these three classes:

public class Base
{
    public enum SampleEnum
    {
        Bar,
        Baz,
    }

    public SampleEnum Type
    {
        get;
        set;
    }
}

public class Bar : Base
{
    public string BarOnly
    {
        get;
        set;
    }
}

public class Baz : Base
{
    public string BazOnly
    {
        get;
        set;
    }
}

Based on the Type property in the json snippet, I'd like to have it deserialize to either Bar or Baz.
My first idea was to first deserialize it to the Base class, and then use its type and a switch statement to deserialize the JSON again to its respective class. (Using Newtonsoft.Json)

var type = JsonConvert.DeserializeObject<Base>(json).Type;
string message = "";
switch (type)
{
    case (Base.SampleEnum.Bar):
        message = JsonConvert.DeserializeObject<Bar>(json).BarOnly;
        break;
    case (Base.SampleEnum.Baz):
        message = JsonConvert.DeserializeObject<Baz>(json).BazOnly;
        break;
}
Console.WriteLine(message);

Needless to say that this process is extremely redundant, tedious and, since the switch statement is hard-coded, not very "dynamic" at all.
Another idea was to use a generic class as the base class instead and passing in the type of the actual class it should deserialize to, but then I end up with the same switch statement to figure out what that class should be.
Since you can't map enums to class types, I also thought about using a Dictionary to map the possible enum values to their class counterparts; this still makes the mapping process hard-coded though.
Is there any way I can dynamically get the corresponding class to deserialize to based on the type property of the json object?

EDIT: There seems to be some confusion about how this is supposed to be used and how the data is fetched; let me provide some background information.
I'm iterating through a directory with a lot of different spreadsheet files, mostly CSVs and XML files. Each of these feeds have a "meta file", describing how to process their content. This includes checksums, delimiters and other information. They also declare of what type their parent file is (CSV, XML etc). Hence, they share a lot of common properties (like the Base class in my example), but also have their own set of properties. They derive from an abstract class that requires them to implement a function that returns an instance of the corresponding feed processing class, initialized with values directly from within the meta class. I hope this makes sense.

Upvotes: 0

Views: 1964

Answers (1)

Davey van Tilburg
Davey van Tilburg

Reputation: 718

@OguzOzgul commenting is correct. I've done this countless of times for objects that are composed with interfaces that need to be serialized and deserialized.

See TypeNameHandling for Newtonsoft: https://www.newtonsoft.com/json/help/html/SerializeTypeNameHandling.htm

Your json file will look ever so slightly different:

{
    "$type": "SomeNamespace.Bar",
    "BarOnly": "This is a string readable when deserialized to the Bar class only, as declared in my type key"
}

If you use

new JsonSerializerSettings
{
    TypeNameHandling = TypeNameHandling.All
}

During serialization, it will add the full type name of all objects to make sure newtonsoft knows what their type is during deserialization (given you use the same settings then). That way you do not have to write your own custom code for type detection.

Upvotes: 1

Related Questions