Динамически присваивать тип списку и заполнять его десериализованным json

#c#

#c#

Вопрос:

У меня есть много классов, которые я использую для хранения объектов определенных типов вместе и выполнения некоторых действий с ними, например. «CarKeeper» или «Employeeekeeper»:

 public class CarKeeper
{
    List<Car> Items;
}

public class EmployeeKeeper
{
    List<Employee> Items;
}
 

Затем я заполняю свойство Items данными из службы web api:

 public async Task Refresh()
{
    if (Items.Any())
    {
        Items.Clear();
    }

    using (var client = new HttpClient())
    {
        string url = Secrets.ApiAddress   "GetEmployees?token="   Secrets.TenantToken   "amp;page=1";

        using (var response = await client.GetAsync(new Uri(url)))
        {
            if (response.IsSuccessStatusCode)
            {
                var userJsonString = await response.Content.ReadAsStringAsync();
                Items = JsonConvert.DeserializeObject<Employee[]>(userJsonString).ToList();
            }
        }
    }
}
 

Данные десериализуются должным образом, и все работает хорошо. Поскольку создание другого подобного класса (например, «DocumentKeeper») означает копирование большого количества кода из любого другого «..Классы «Хранитель» (они разделяют 90% кода), я хочу создать единый класс «Хранитель» для обработки всех объектов.

Проблема в том, что мне нужно как-то сообщить классу «Хранитель», какой тип он сохраняет, потому что иногда ему приходится сохранять List<Employee> , а иногда и список других типов. Я думал о передаче типа в contstructor «Keeper» и … и я потерял, что с ним делать позже 🙂 Я также пытался сделать все списки списком, и это вроде работает, но далеко не идеально.

Как я могу заставить свой код работать?

 public class Keeper
{
    List<T> Items;

    public Keeper(Type T)
    {
        //make Items a list of int if int is passed as T
    }

    public async Task Refresh()
    {
        if (Items.Any())
        {
            Items.Clear();
        }

        using (var client = new HttpClient())
        {
            string url = Secrets.ApiAddress   "GetItems?token="   Secrets.TenantToken   "amp;page=1";
            using (var response = await client.GetAsync(new Uri(url)))
            {
                if (response.IsSuccessStatusCode)
                {
                    var userJsonString = await response.Content.ReadAsStringAsync();
                    //how to put the passed type to DeserializeObject<>?
                    Items = JsonConvert.DeserializeObject<T[]>(userJsonString).ToList();
                }
            }
        }
    }
}
 

Ответ №1:

Вы хотите передать тип как универсальный тип, а не как Type объект:

 public abstract class KeeperBase<T>
{
    List<T> Items;

    public Keeper() { }

    protected abstract string GetRefreshApi { get; }
    public async Task Refresh()
    {
        if (Items.Any())
        {
            Items.Clear();
        }

        using (var client = new HttpClient())
        {
            using (var response = await client.GetAsync(new Uri(GetRefreshApi)))
            {
                if (response.IsSuccessStatusCode)
                {
                    var userJsonString = await response.Content.ReadAsStringAsync();
                    //how to put the passed type to DeserializeObject<>?
                    Items = JsonConvert.DeserializeObject<T[]>(userJsonString).ToList();
                }
            }
        }
    }
}
public class CarKeeper : KeeperBase<Car>
{
    protected override string GetRefreshApi => Secrets.ApiAddress   "GetCars?token="   Secrets.TenantToken   "amp;page=1";
}
public class EmployeeKeeper : KeeperBase<Employee>
{
    protected override string GetRefreshApi => Secrets.ApiAddress   "GetEmployees?token="   Secrets.TenantToken   "amp;page=1";
}
 

И вы можете использовать их следующим образом:

 var carKeeper = new CarKeeper();
await carKeeper.Refresh();
foreach(var car in carKeeper.Items)
{
    // ...
}