How do I make this JSON load method generic

Viewed 122

I have multiple JSON files with data and multiple classes with properties mapped to fields in the JSON files. I have a generic method for loading the JSON like this:

public static TResult LoadFromJSON<TResult>(string pathToJSON)
{
    using (var reader = new StreamReader(pathToJSON))
    {
        var json = reader.ReadToEnd();
        var records = JsonConvert.DeserializeObject<TResult>(json);
        return records;
    }
}

and then another method that passes in the Class object I am targeting into the above LoadFromJSON

public SortingData GetJSONTestData()
{
    var pathJSON = @"..\..\TestData\sortData.json";
    var sortCriteriaJSON = TestDataLoader.LoadFromJSON<SortingData>(pathJSON);
    return sortCriteriaJSON;
}

what I want to do is make that second method generic, so instead of having SortingData class (in 2 places) and sortData.json file, I can pass in the Class (in both places) and the JSON file dynamically..... so I don't have to duplicate the method over and over just for a different class. So something like this:

    public <dynamicObject> GetJSONTestData()
    {
        var pathJSON = @"..\..\TestData\<dynamic json file>";
        var sortCriteriaJSON = TestDataLoader.LoadFromJSON<dynamicObject>(pathJSON);
        return sortCriteriaJSON;
    }

Not sure how to go about this. Any ideas?

2 Answers

You can use typeof and string concatenation to achieve this, like so:

public T GetJsonTestData<T>()
{
    // Say T is SortingData, name here is "SortingData"
    var name = typeof(T).Name;
    // After this, name is "sortingData"
    name = Char.ToLowerInvariant(name[0]) + name.Substring(1);

    var path = $@"..\..\TestData\{name}";
    return LoadFromJson<T>(path);
}

Then you could call it like so:

// This would read "..\..\TestData\sortingData.json"
var sortingData = GetJsonTestData<SortingData>();

// This would read "..\..\TestData\fooBar.json"
var whatever = GetJsonTestData<FooBar>();

It sounds like you want to be able to map types to file names. You can either resolve the file names by convention, or load the mapping through some configuration.

In the example below the configuration is hard coded, but it wouldn't be much to load it from an appSettings file (demonstrating that is beyond the scope of this question). With the configuration, it's pretty trivial to get the file name from the dictionary and pass it to LoadFromJson.

public class TestDataLoader
{
    private readonly string basePath = @"..\..\TestData";

    private readonly Dictionary<Type, string> fileNameRegistry = new() 
    {
        { typeof(SortingData), "sorting_data.json" }
    };

    public TResult GetJSONTestData<TResult>()
    {
        var typefileName = fileNameRegistry[typeof(TResult)];
        var path = Path.Combine(basePath, typeFileName);
        return LoadFromJSON<TResult>(path);
    }

    public static TResult LoadFromJSON<TResult>(string pathToJSON)
    {
        using (var reader = new StreamReader(pathToJSON))
        {
            var json = reader.ReadToEnd();
            var records = JsonConvert.DeserializeObject<TResult>(json);
            return records;
        }
    }

}
Related