当数组可以包含字符串或复杂对象时,反序列化Json?

时间:2018-11-29 14:19:39

标签: c# json.net

我正在尝试在C#应用程序中读取json片段。

在该片段中,有一个可以包含简单字符串或复杂对象的数组。这是因为所包含的对象只有一个强制性字符串,其他字段是可选的。因此,为了简化json,数组可以包含字符串(=默认参数)或复杂对象。

这是一个示例json:

{
    "Config1": [
        "Simple string 1",
        "Simple string 2",
        {
            "Data": "Complex object",
            "OptionalField": "some option",
            "AnotherOption": 42
        }
    ],
    "Config3": [
        "Simple string 3",
        "Simple string 4",
        {
            "Data": "Complex object 2",
            "OptionalField": "some option",
            "AnotherOption": 12
        }
    ]    
}

相应的C#模型:

public class Config : Dictionary<string, ConfigItem[]>
{
}
public class ConfigItem
{
    public ConfigItem()
    {
    }

    public ConfigItem(string data)
    {
        this.Data = data;
    }

    public string Data { get; set; }

    public string OptionalField { get; set; }

    public int AnotherOption { get; set; }
}

在我的示例中,仅Data字段是必填字段。提供字符串时,必须调用带有单个字符串参数的构造函数。提供复杂的json对象时,必须运行标准反序列化。

例如,这两个json片段是等效的(在数组中):

"Config4": [
    "This is a string",
    {
        "Data": "This is a string",
        "OptionalField": null,
        "AnotherOption": 0
    }
]

如何实现我的目标?

现在,我尝试实现一个自定义转换器:

[JsonConverter(typeof(StringToComplexConverter))]
public class ConfigItem
{
    // Properties omiited
}

public class StringToComplexConverter : JsonConverter<ConfigItem>
{
    public override bool CanWrite => false;

    public override ConfigItem ReadJson(JsonReader reader, Type objectType, ConfigItem existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        if(reader.TokenType == JsonToken.String)
        {
            var ctor = objectType.GetConstructor(new[] { typeof(string) });
            return (ConfigItem)ctor.Invoke(new[] { (string)reader.Value });
        }
        else
        {
            // What to put in the else ?
        }
    }

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

这实际上适用于字符串。但是,我没有找到要放在else语句中的内容。是否可以通过ReadJson方法将转发到标准反序列化?

如果在我的else语句中放入return serializer.Deserialize<ConfigItem>(reader);,它将以无限循环结束。

也尝试了return serializer.Deserialize<JObject>(reader).ToObject<ConfigItem>();,但没有成功。

1 个答案:

答案 0 :(得分:1)

最后找到了一种方法。这是我的else声明:

        else
        {
            var result = new ConfigItem();
            serializer.Populate(reader, result);
            return result;
        }

奖金:这是转换器的通用变体,可以应用于具有无参数构造函数和具有字符串参数的构造函数的任何类:

public class StringToComplexConverter<TObject> : JsonConverter<TObject>
{
    public override bool CanWrite => false;

    public override TObject ReadJson(
        JsonReader reader,
        Type objectType,
        TObject existingValue,
        bool hasExistingValue,
        JsonSerializer serializer
        )
    {
        if (reader.TokenType == JsonToken.String)
        {
            var ctor = objectType.GetConstructor(new[] { typeof(string) });
            return (TObject)ctor.Invoke(new[] { (string)reader.Value });
        }
        else
        {
            var result = (TObject)Activator.CreateInstance(objectType);
            serializer.Populate(reader, result);
            return result;
        }
    }

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