[C#] Deserialize JSON to an interface with JsonConverter
On C#, interfaces cannot be instantiated directly. To deserialize interfaces, you need to choose a class that implements that interface, so the deserializer can fill the corresponding properties.
Below there's an example where the code checks an attribute Type inside the JSON to determine what class should be instanciated.
JSON Example
{
"FirstValue": {
"Type": "TypeA",
"StringContent": "Example"
},
"SecondValue": {
"Type": "TypeB",
"IntegerContent": 123
}
}
Deserialized structure
public interface ICustomInterface
{
string Type { get; }
}
public class DeserializationResult
{
public ICustomInterface? FirstValue { get; set; }
public ICustomInterface? SecondValue { get; set; }
}
Multiple interface implementations
public class ImplementationTypeA : ICustomInterface
{
public string Type { get; set; }
public string StringContent { get; set; }
}
public class ImplementationTypeB : ICustomInterface
{
public string Type { get; set; }
public int IntegerContent { get; set; }
}
Implementing the CustomJsonConverter
using System.Text.Json;
public class CustomJsonConverter : JsonConverter<ICustomInterface?>
{
public override ICustomInterface? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var node = JsonNode.Parse(ref reader);
var type = node!["Type"]?.GetValue<string?>();
if(type == "TypeA")
return node.Deserialize<ImplementationTypeA>();
if(type == "TypeB")
return node.Deserialize<ImplementationTypeB>();
return null;
}
public override void Write(Utf8JsonWriter writer, ICustomInterface? value, JsonSerializerOptions options)
{
JsonSerializer.Serialize(writer, (object?)value, options);
}
}
Consuming the JsonConverter
using System.Text.Json;
public void ExecuteDeserialization(string json)
{
var jsonOptions = new JsonSerializerOptions();
jsonOptions.Converters.Add(new CustomJsonConverter());
var resultInstance = JsonSerializer.Deserialize<DeserializationResult>(json, jsonOptions);
var serializedJson = JsonSerializer.Serialize(resultInstance, jsonOptions);
}