Newtonsoft JsonConverter для преобразования строки или объекта в объект - PullRequest
2 голосов
/ 04 августа 2020

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

{
    "value": "a string"
}

- или -

{
    "value": {
        "text": "a string"
        // there are other properties, but for successful deserialization I only need text present
    }
}

И я ожидаю чтобы иметь возможность успешно преобразовать в объект, MyObject:

public class MyObject
{
    [JsonProperty("text")
    public string Text { get; set; }
}

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

public class MyObjectConverter : JsonConverter
{
    public override bool CanWrite { get => false; }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(string) || objectType == typeof(MyObject);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var value = reader.Value?.ToString();
        if (string.IsNullOrWhiteSpace(value))
        {
            return null;
        }

        try
        {
            return JObject.Parse(value).ToObject<MyObject>();
        }
        catch (Exception)
        {
            return new MyObject
            {
                Text = value
            };
        }
    }
}

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

РЕШЕНИЕ:

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.String)
        {
            return new MyObject
            {
                Text = reader.Value?.ToString()
            };
        }
        else if (reader.TokenType == JsonToken.StartObject)
        {
            JObject obj = JObject.Load(reader);
            return obj.ToObject<MyObject>();
        }
        else
        {
            return null;
        }
    }

1 Ответ

2 голосов
/ 04 августа 2020

Ваш объект не имеет такой структуры, как ожидаемый вами ввод. Во втором случае MyObject должен выглядеть так:

// this is ugly
public class MyObject
{
    public Value value{get;set;}

    public class Value{
         public string text {get;set;}
    }
}

Если вы хотите иметь только объект с одним свойством Text, как вы это делаете сейчас, вы можете сделать что-то вроде этого:

public override object ReadJson(JsonReader reader, Type objectType, object 
    existingValue, JsonSerializer serializer)
{
    JObject obj = JObject.Load(reader);
    var value = obj["value"];

    if(value is JObject)  // this will be true if the value property is a nested structure
       return new MyObject(){Text=value["text"]};  // could also do value.ToObject<MyObject>() if you need more properties
    else
       return new MyObject(){Text=value};
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...