JSON десериализация для полиморфных результатов - PullRequest
0 голосов
/ 31 мая 2018

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

    {
"hasmoredata":true,
      "current_page": 1,
      "page_size": 20,
      "total_pages": 5,
      "items": [
          {
            "user_id": "1",
            "username": "carl",
            "first_name": "carl",
           }
      ]
    }

    {
"hasmoredata":true,
      "current_page": 1,
      "page_size": 10,
      "total_pages": 2,
      "items": [
          {
            "course_id": "10",
            "course_name": "Math",
            "duration": "3h",
           }
      ]
    }

Я хотел бы иметь два класса, которые расширяют абстрактный класс, который собирает общие свойства.Примерно так (в C #):

 public abstract class CursorResult
    { 

        [JsonProperty("current_page")]
        public int CurrentPage { get; set; }

        [JsonProperty("page_size")]
        public int PageSize { get; set; }

        [JsonProperty("total_pages")]
        public int TotalPages { get; set; }

[JsonProperty("hasmoredata")]
            public bool HasMoreData{ get; set; }
        }

public class UsersList : CursorResult
    {
        [JsonProperty("items")]
        List<User> Users { get; set; }
    }

public class CoursesList : CursorResult
    {
        [JsonProperty("items")]
        List<Courses> Courses { get; set; }
    }

Теперь проблема в том, что мне нужно написать функцию, которая собирает весь результат (все страницы элементов) и объединяет эти результаты в одно:

private CursorResult GetEntireResult(string apiURL)
        {
            Cursor c = new Cursor(1, pageSize);

            CursorResult result = TryDeserializeCursorResult(CallRestFulAPI(apiURL + c.GetCursorParametersString, Method.GET));

            c.Hashcode = result.CursorHashCode;

            while (result.HasMoreData)
            {
                c.CurrentPage += 1;
                result.AddItems(TryDeserializeCursorResult(CallRestFulAPI(apiURL + c.ParametersString, Method.GET)));
            }

            return result;
        }

но я понятия не имею, как написать функцию AddItem для добавления пользователей или курсов в зависимости от результата API.

Заранее благодарен за любую помощь!

Лапо

1 Ответ

0 голосов
/ 31 мая 2018

Пара вещей:

  1. С вашим текущим кодом, если вы используете сериализатор по умолчанию, при десериализации вы не собираетесь захватывать «элементы», потому что выповторно десериализовать в CursorResult, для которого не определено свойство 'items'.Сериализатор не знает автоматически о производных типах.Также я бы рекомендовал переименовать классы UserList и CoursesList в UserCursorResult / CourseCursorResult.Классы не являются списками, они содержат списки.

  2. Вот код, который будет различать сериализованные (под) типы json:

            string yourJsonString = @"{ 'hasmoredata':true,'current_page': 
            1,'page_size': 20,'total_pages': 5,'items': [{'user_id': 
            '1','username': 'carl','first_name': 'carl'}]}";
    
            JSchemaGenerator generator = new JSchemaGenerator();
            JSchema userSchema = generator.Generate(typeof(UsersList));
            JSchema courseSchema = generator.Generate(typeof(CoursesList));
            JToken jObject = JObject.Parse(yourJsonString);
    
            if (jObject.IsValid(courseSchema))
            {
                CoursesList courseList = JsonConvert.DeserializeObject<CoursesList>(yourJsonString);
                //do stuff with CourseList
            }
            else if (jObject.IsValid(userSchema))
            {
                UsersList userList = JsonConvert.DeserializeObject<UsersList>(yourJsonString);
                //do stuff with UsersList
            }
    
...