Given the following json
{
"filters": [
{ "filterType": "fooFilter", "min": 1, "max": 5, "size":3 },
{ "filterType": "barFilter", "multiplier": "1.953283", "average": "5.732837" },
{ "filterType": "bazFilter", "limit": 10, "createdBefore": "1641942136" }
]
}
I want to create an array of filter objects like so:
public class MyRootClass
{
public IFilter[] Filters { get; init; } = default!;
}
public interface IFilter
{
public string Name { get; }
}
public class FooFilter : IFilter
{
public string Name => nameof(FooFilter);
public int Min { get; init; }
public int Max { get; init; }
public int Size { get; init; }
}
public class BarFilter : IFilter
{
public string Name => nameof(BarFilter);
public decimal Multiplier { get; init; }
public decimal Average { get; init; }
}
public class BazFilter : IFilter
{
public string Name => nameof(BazFilter);
public int Limit { get; init; }
public long CreatedBefore { get; init; }
}
In the above example, I made Name
as a auto get readonly property to show that the value from from the json does not need to be stored. I included several types in each 'IFilter' type that should have built in converters already (ie. createdBefore is a string in json (quoted), but the built in converters will handle conversion to long automatically).
Also to note, there will only ever be either 0 or 1 of each filter type in the array, so there will be no collisions with multiple filters that are the same type.
What I need help with here is writing a JsonConverter that will read the "filterType" in each element of the array in 'filters' and create instances of that filter.
Producing an output similar to this:
var filters = new List<IFilter> {
new FooFilter { Min = 1, Max = 5, Size = 3 },
new BarFilter { Multiplier = (decimal) 1.953283, Average = (decimal) 5.732837 },
new BazFilter { Limit = (int) 10, CreatedBefore = (long) 1641942136 }
}
How can I build the converter to automatically convert each of the types based on the 'filterType' value inside the individual array. I am thinking along the lines of a switch / case inside of the converter for simplicity, but bonus gold stars for using reflection (in this case I have a pretty short list of Filter types, (less than 10), however down the road, I will be adding a plugin system to (other parts of) my application that could benefit from dynamic conversion using reflection, but I am pretty solid in reflection stuff, so I can do that later if you could explain how to just write the converter portion for this.
Also I am specifically using System.Text.Json
libraries as the rest of my application uses that and I don't want to intermix other libraries such as NewtonSoft or Macross.Json.Extensions. I am using the latest .NET6 (.NET Core) and C#10.
Edit:
As I may not have been clear, (I believe this needs to be done with a JsonConverter) so it is converted automatically as this is how I am deserializing:
using (var client = new HttpClient());
var response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
var myRootClass = await response.Content.ReadFromJsonAsync<MyRootClass>();
}
else
{
// Handle errors accordingly
}
so the ReadFromJsonAsync<T>
method is what I am using to deserialize the json