【问题标题】:Deserialise Json when an array can contain either string or complex object?当数组可以包含字符串或复杂对象时反序列化Json?
【发布时间】:2018-11-29 14:19:39
【问题描述】:

我正在尝试在 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&lt;ConfigItem&gt;(reader);,它会以无限循环结束。

也试过return serializer.Deserialize&lt;JObject&gt;(reader).ToObject&lt;ConfigItem&gt;();,没有成功。

【问题讨论】:

  • 我认为你需要继承非泛型JsonConverter
  • @Amy:不确定你的意思。使用非泛型转换器,我仍然得到一个无限循环。
  • 实现通用转换器意味着您只能返回该类型的对象。你不能打电话给serializer.Deserialize...,因为它只使用你的转换器,但我有理由确定你需要实现非通用转换器。
  • this question。这对您反序列化对象有帮助吗?
  • 另见this question。这个可能是骗子。我不知道。今天早上我还没有喝咖啡:(

标签: c# json.net


【解决方案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();
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-12-09
    • 1970-01-01
    • 1970-01-01
    • 2019-12-28
    • 1970-01-01
    • 2017-12-04
    • 1970-01-01
    相关资源
    最近更新 更多