Десериализовать строку в массив типа десериализации, используя json.net


У меня есть вход в JSON

{"QtyEqualsQtyWorked":0,"ReasonCode":"IN"}

и мой класс

public class LoadForMovementOpt
{
    public bool QtyEqualsQtyWorked { get; set; }
    public string[] ReasonCode { get; set; }
}

Недвижимость ReasonCode должен быть массив по некоторым причинам я не могу спорить, но в JSON, это может быть как строка, так и строка[]. Поэтому я написал конвертер, который реально работает, но может быть улучшено:

class LoadForMovementConverter : JsonConverter
{
    public override bool CanConvert(Type objectType) { return true; }
    public override bool CanWrite
    {
        get
        {
            return false;
        }
    }
    public override bool CanRead
    {
        get
        {
            return true;
        }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JToken token = JToken.Load(reader);
        var reasonToken = token["ReasonCode"];

        if(reasonToken == null)
        {
            return token.ToObject(objectType);
        }

        if(reasonToken.Type == JTokenType.Array)
        {
            return token.ToObject(objectType);
        }
        else
        {
            var QtyEqualsQtyWorkedToken = token["QtyEqualsQtyWorked"];
            return 
            new LoadForMovementOpt 
            {
                QtyEqualsQtyWorked = 
                    QtyEqualsQtyWorkedToken
                        .ToObject<bool>(), 
                ReasonCode = 
                    new string[] 
                    {
                        reasonToken.ToObject<string>() 
                    }
            };
        }
    }
}

Есть ли способ, чтобы улучшить его?



2979
3
задан 7 февраля 2018 в 12:02 Источник Поделиться
Комментарии
2 ответа

У вас есть доступ к JsonReader и классы JToken? Если это так, рассмотрим следующие API. Есть много логики завязано на нынешний метод ReadJson что может быть (ИМО) лучше отделить оттуда. Вы, конечно, должны создать/реализовать/переопределить
соответствующие базовые классы и методы: обратите внимание, как много беспорядка отделена и перенесена на завод с помощью следующих API? И соответствующих JTokens будете точно знать, что делать, когда вы посылаете метод ToObject к нему - нет необходимости проверять тип, или чтобы проверить, если это массив, так как завод будет заботиться о этой логики. Единственный минус заключается в том, что это может быть немного раздражает, если вы должны бросить свою собственную реализацию JsonReader.

// A so-so API that is marginally better
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JToken token = JToken.LoadMovementConverter(reader);
token.ToObject();
}

// even more ideal API:
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JToken token = reader.GetMovementConverterJToken();
token.ToObject();
}

// create new JToken types:
public class JTokenNullReason : JToken
{
public override object ToObject()
{
throw new NotImplementedException();
}
}

public class JTokenArray : JToken
{
public override object ToObject()
{
throw new NotImplementedException();
}
}

public class JTokenEqualsQtyWorked : JToken
{
public override object ToObject()
{
throw new NotImplementedException();
}
}

И тогда абстрактный класс, что-то вроде этого:

public abstract class JToken 
{
public abstract object ToObject();

public static JToken Load(JsonReader reader )
{
// not ideal because an abstract ReasonCode class instance method
// could return the required JToken via a factory method.
// you could certainly refactor this code, or, even better:
// ask the reader itself to get you the correct JToken.

string reasonCode = reader.GetReasonCode();
switch (reasonCode)
{
case null:
return new JTokenNullReason();
break;
case "Array":
return new JTokenArray();
break;
default:
return new JTokenEqualsQtyWorked();
break;
}
}
}

1
ответ дан 7 февраля 2018 в 10:02 Источник Поделиться

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

[JsonConverter(typeof(StringValueToArrayConverter))]
public string[] ReasonCode { get; set; }

Реализация этого конвертера будет наследовать Newtonsoft.Json.JsonConverter и реализовать интерфейс.

ReadJson метод этот конвертер будет называться при десериализации этого имущества, и может быть как простой, как:

return new string[] { reader.Value.ToString() };

но причины могут быть настолько сложными, насколько это необходимо.

Существует также WriteJson метод для сериализации и CanConvert метод для проверки.

1
ответ дан 12 февраля 2018 в 11:02 Источник Поделиться