反序列化时是否可以将字段保留为原始文本?

Is it possible to leave fields as raw text when deserializing?

我有json这样的

{
    "guid": "b1e3c29f-066f-417b-b6b6-795ffae90f0a",
    "status": "complete",
    "type": "colors",    
    "results": {
        "events": [
            {
                "title": "event1",
                "other": {
                    "Red": "red",
                    "Green": "green",
                    "Blue": "blue"
                }
            },
            {
                "title": "event2",
                "other": {
                    "Yelow": "yellow",
                    "Orange": "orange"
                }
            }
        ]
    }
}

和类反序列化看起来像这样

public class Other
{
    public string Red { get; set; }
    public string Green { get; set; }
    public string Blue { get; set; }
    public string Yelow { get; set; }
    public string Orange { get; set; }
}

public class Event
{
    public string title { get; set; }
    public Other other { get; set; }
}

public class Results
{
    public List<Event> events { get; set; }
}

public class Root
{
    public string guid { get; set; }
    public string status { get; set; }
    public string type { get; set; }
    public Results results { get; set; }
}

当我用

反序列化这个json时
var root = JsonConvert.DeserializeObject<Root>(JsonContent); 

一切正常。

问题是json段"Other"的内容是可变的,我不知道它的完整内容。
我还需要把这个 类 放入数据库中。

有没有办法将 json 部分 "Other" 反序列化为一个带有原始文本的字符串字段,并且看起来像这样:

public class Other
{
    public string AllFieldsFromOtherSectionAsRawText { get; set; }
}

Other 不是字典表示吗?

你不能把它写成字典吗

public Dictionary<String,String> other { get; set; }

示例:

    [Newtonsoft.Json.JsonExtensionData]
    public System.Collections.Generic.IDictionary<string, string> other

根据文档,您 DeserializeObject 类型为 Dictionary:

JsonConvert.DeserializeObject<Dictionary<string, string>>(json);

https://www.newtonsoft.com/json/help/html/DeserializeDictionary.htm

如果您这样定义 Other class:

public class Other
{
    public Other(string rawData)
    {
        Content = rawData;
    }
    public string Content { get; }
}

然后您可以编写一个自定义 JsonConverter,它将把您的 other 节点视为 string:

class ObjectToStringJsonConverter : JsonConverter
{
    private readonly Type theType;
    public ObjectToStringJsonConverter(Type type) => theType = type;

    public override bool CanConvert(Type objectType) => objectType == theType;

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

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JToken token = JToken.Load(reader);
        if (token.Type == JTokenType.Object)
        {
            return Activator.CreateInstance(theType, args: token.ToString()); 
        }
        throw new NotSupportedException("The related node is not object");
    }
}

这里唯一的技巧是这一行:

  • Activator.CreateInstance(theType, args: token.ToString());
  • 这里我们创建一个新的 Other 实例,并将 other 节点的字符串表示形式传递给构造函数。

那么用法将是这样的:

var root = JsonConvert.DeserializeObject<Root>(json, new[] { new ObjectToStringJsonConverter(typeof(Other)) });

从代码中删除 class Other,并修复事件 class

public class Event
{
    public string title { get; set; }
    [JsonProperty(PropertyName = "other")]
    public Dictionary<string, string> otherDict { get; set; }
    
    [Newtonsoft.Json.JsonIgnore]
    public IEnumerable<string> Other
    {
        get { return  otherDict.Values.ToArray(); }
    }

    [Newtonsoft.Json.JsonIgnore]
    public string AllFieldsFromOtherSectionAsRawText
    {
        get { return string.Join(",", Other);  }
    }
}

输出

{
  "guid": "b1e3c29f-066f-417b-b6b6-795ffae90f0a",
  "status": "complete",
  "type": "colors",
  "results": {
    "events": [
      {
        "title": "event1",
        "other": {
          "Red": "red",
          "Green": "green",
          "Blue": "blue"
        },
        "AllFieldsFromOtherSectionAsRawText": "red,green,blue"
      },
      {
        "title": "event2",
        "other": {
          "Yelow": "yellow",
          "Orange": "orange"
        },
        "AllFieldsFromOtherSectionAsRawText": "yellow,orange"
      }
    ]
  }
}