Как сбросить JsonProperties в классе с новой строкой JSON - PullRequest
0 голосов
/ 12 января 2019

Я десериализовал JSON в объект c #, но с неполным JSON, так что некоторые свойства отсутствуют. Во время десериализации объекта у меня нет доступа к полному JSON. Я могу получить полный JSON, сделав еще один вызов API, но я не хочу делать этот вызов, если мне не нужно.

Я бы хотел, чтобы мои средства получения работали так, чтобы они возвращали свойство, если оно не равно нулю. Если это значение равно NULL, он должен вызвать API, чтобы получить полный JSON и обновить все JsonProperties в классе, а затем вернуть запрошенное свойство.

public class Car
{
    private string _make;
    private string _model;

    [JsonProperty("make")]
    public string Make
    {
        get
        {
            if (_make != null)
            {
                return _make;
            }
            else
            {
                UpdateProperties();
                return _make;
            }
        }
    }

    [JsonProperty("model")]
    public string Model
    {
        get
        {
            if (_model != null)
            {
                return _model;
            }
            else
            {
                UpdateProperties();
                return _model;
            }
        }
    }

    [JsonProperty("self")]
    public Uri Self { get; set; }

    public void UpdateProperties()
    {
    }
}

В методе UpdateProperties (), приведенном выше, я могу заставить его использовать свойство Self для получения и десериализации нового экземпляра класса Car, но вместо этого я хочу обновить свойства текущего экземпляра класса Car. Я могу сделать это вручную, заново установив каждое свойство индивидуально, но, поскольку мне нужно сделать это для многих классов, я был бы признателен за лучший способ. Это возможно?

Или я все делаю неправильно?

EDIT:

Вот пример JSON, который API должен вернуть. Допустим, я звоню, чтобы получить информацию об автопарке. Это вернуло бы:

{
    "details" : "something"
    "car": {
        "make": "Ford",
        "self": "https://..."
         }
    "truck": {
         "age": 30,
         "self": "https://..."
         }
}

где при доступе к URL-адресу, предоставленному car.self, он вернет следующий JSON:

{
    "make" : "Toyota",
    "model" : "Camry",
    "self" : "https://..."
}

Ответы [ 2 ]

0 голосов
/ 13 января 2019

Итак, позвольте мне предложить другую точку зрения. Описание проблемы кажется достаточно простым - у меня есть два вызова API, один из которых возвращает частичный объект, а другой - полный объект. Я не хочу делать два звонка, если мне не нужно. Итак, я просто сделаю второй звонок и "заполню детали", если понадобится, верно?

Неправильно.

Предлагаемый подход не очень хорошая идея.

Это сходит с рельсов с самого начала с дизайном API. Объекты, возвращаемые API, не должны быть настолько сложными, чтобы требовать множественных вызовов для возврата «полного» объекта, как описано в коде. Но давайте предположим, что у меня нет контроля над дизайном API - что мне делать?

Программисты часто сталкиваются с проблемой противодействия плохо спроектированному API. Они создают негерметичные абстракции , подобные описанной в этой задаче, где существует сильное желание "замаскировать" плохой дизайн API. Проблема в том, что не все плохие проекты могут быть скрыты. Это один

Здесь предлагается ввести болезненный побочный эффект средства доступа get. Возможно, это худший способ решения проблемы плохого проектирования API. Типичный метод get возвращается с незначительным количеством времени - это простой доступ к памяти. Предполагаемый метод доступа get может потенциально занять несколько секунд, чтобы вернуться, он может потерпеть неудачу, он может вызвать исключение. Хуже всего то, что нет никаких указаний вызывающей стороне, что на самом деле это доступ к внешнему интерфейсу. В конце концов, состояние вашего объекта не является детерминированным, что, вероятно, худшее что вы можете иметь в программе.

Если это было не так уж и плохо, в аксессорах get не предусмотрено асинхронных операций, которые часто встречаются при работе с удаленными API. Пользовательский опыт пострадает. Используя этот подход, я на самом деле рассмотрю одну проблему и создаю новую проблему везде, где используется этот класс.

Лучший подход:

API имеет две отдельные функции, поэтому на самом деле это подразумевает два отдельных типа результатов. Я бы создал один тип для частичного класса и второй тип для полного класса. В конце концов, я пишу код - и если код не имеет привычки переписывать сам себя, во время написания я должен знать, нужно ли мне полное или частичное представление объекта.

Чтобы получить полное представление, я предоставлю отдельный доступ к API с соответствующими методами, обеспечивающими асинхронное выполнение (например, наблюдаемые). Это будет иметь дополнительное преимущество, позволяя мне исследовать (с помощью функции «где используется»), где в программе используются эти различные вызовы API. Это может послужить основанием для того, чтобы я вернулся к конструктору API и предложил изменить дизайн в зависимости от того, как я его использую.

0 голосов
/ 13 января 2019

Единственный способ при текущей настройке сбросить все свойства вручную.

Вы правы, что хотите, чтобы это было автоматическим, так как это много стандартного кода. Это общая проблема, и наиболее распространенным решением является использование шаблона DTO объекта передачи данных *1003* или .

Вы бы представили новый класс с именем CarDto, и вместо Car, предоставляющего закрытые поля, он бы выставил свойства CarDto.

См. Ниже:

public class Car {

    private CarDto _dto = null;
    public Car(CarDto dto = null) {
        //If we pass in a dto, use it, otherwise create a new one
        _dto = dto ?? new CarDto();
    }

    [JsonProperty("make")]
    public string Make {
        get {
            if (_dto.Make == null) {
                UpdateProperties();
            }
            return _dto.Make;
        }
    }

    [JsonProperty("model")]
    public string Model {
        get {
            if (_dto.Model == null) {
                UpdateProperties();
            }
            return _dto.Model;
        }
    }

    [JsonProperty("self")]
    public Uri Self { get; set; }

    public void UpdateProperties() { 
        //The API would return a CarDto.
        CarDto newDto = APICall(); //Mock code
        _dto = newDto;
    }
}

public class CarDto {
    public string Make { get;set; }
    public string Model { get;set; }
}

Так что теперь, если у вас когда-либо будет нулевое свойство, вы сделаете вызов UpdateProperties. Затем будет возвращено новое CarDto, которое вы используете в качестве личного _dto поля.

Это СУПЕР полезный и распространенный шаблон, который значительно упрощает процесс, поэтому его очень удобно применять и практиковаться! Дайте мне знать, если что-то неясно.

...