Подтвердить что ты не робот

Динамически десериализовать свойство в RestSharp

Я играю с API Harvest, и я пытаюсь автоматически сопоставить объекты как можно проще, к сожалению, когда я делаю запрос типа GET /projects, он генерирует такой результат:

[{
    project: {
        name: "Test"
    }
},
{
    project: {
        name: "Test 2"
}]

В RestSharp я не могу напрямую это сделать:

client.Execute<List<Project>>(request)

Потому что он будет искать свойство под названием Project. Поэтому я должен создать другой класс, обладающий этим свойством, и называть его следующим образом:

client.Execute<List<ProjectContainer>>(request)

Я не хочу создавать класс "контейнера" для каждого объекта, поэтому я решил, что нашел умное решение, чтобы сделать один класс, который я могу использовать для всех:

public class ListContainer<T> where T : IHarvestEntity
{
    public T Item { get; set; }
}

Но, конечно, десериализатор понятия не имеет, что ему нужно сопоставить имя объекта (или "Проект" ) с свойством Item. В документации restsharp я обнаружил, что могу использовать [DeserializeAs(Name = "CustomProperty")], чтобы сообщить десериализатору, какое поле будет отображено для этого свойства. Однако атрибуты допускают только константы, что означает, что я не могу:

[DeserializeAs(Name = typeof(T).FullName)]
public T Item { get; set; }

Кто-нибудь знает умное решение? Так что мне не нужно создавать 10 различных классов контейнеров?

4b9b3361

Ответ 1

Я предлагаю вам использовать эквивалент XPath для Json. С помощью Json.NET вы можете parse строку и создать динамический объект.

С SelectToken вы можете запрашивать значения или использовать Linq.

Код выглядит примерно так (я его не тестировал):

// execute the request
RestResponse response = client.Execute(request);
var content = response.Content; // raw content as string

JObject o = JObject.Parse(content);

IList<string> projectNames = o.SelectToken("project").Select(s => (string)s.name).ToList();

Вы можете закодировать пути или настроить пути в любом случае.

--- Редактировать ---

Вот пример, который я тестировал, преобразование строки json в список проектов.

var projects = JArray.Parse(response.Content).Select(r => new Project(r["project"]["name"].Value<string>())).ToList();

Ответ 2

Чтобы это было очень просто, вы можете использовать List<dynamic> и получить доступ к свойствам/свойствам по имени с помощью однострочного интерфейса.

var names = client.Execute<List<dynamic>>(request).Data.Select(
              item => item["project"]["name"]).ToList(); // list of names

Если этого недостаточно, вы можете импровизировать свой собственный картограф и извлечь коллекцию, например. Project экземпляры:

var projects = client.Execute<List<dynamic>>(request).Data.Select(
                 item => Map<Project>(item)).ToList(); // list of Project instances

где метод Map может быть чем-то вроде

public T Map<T>(dynamic item) where T : class
{
    // inline for clarity
    var mappings = new Dictionary<Type,Func<dynamic,object>>
        {
            { typeof(Project), map => new Project(map["project"]["name"]) }
        };

    return (T)mappings[typeof(T)].Invoke(item);
}

данный Project определяется как

public class Project
{
    public Project(string name)
    {
        Name = name;
    }
    public string Name { get; set; }
}