Newtonsoft JSON序列化模板

时间:2016-05-30 13:19:07

标签: c# json

我正在尝试将类序列化为JSON字符串。首先,我的实际代码:

// Note that this class is inside a PCL
public class CommunicationMessage {

    public String Key { get; set; }

    public String Value { get; set; }

    public List<CommunicationMessage> Childs { get; set; }
}

这是一个可以转换为xml的模板,如下所示:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<myproject>
    <communicationmessage>
        <header>
             <participantid>1</participantid>
             <deviceid>54325</deviceid>
             <devicetype>Smartphone Samsung 4500</devicetype>
             <timestamp>3456453445</timestamp>
             <location>343-5343-64353</location>
             <networkid>32</networkid>
             <messageid>4003</messageid>
        </header>
        <data>
        </data>
    </communicationmessage>
</myproject>

如您所见,变量 Key 是一个Xml-Element,名为例如 communicationmessage

现在你想要将模板转换为JSON字符串,但是我肯定得到的是元素 communicationmessage 元素&#34; Key&#34;:&#34; communicationmessage&#34; 即可。有没有办法为像&#34; mymessage&#34;这样的元素获得一些东西:&#34;这是一个测试&#34; 其中&#34; mymessage&#34;是关键和&#34;这是一个测试&#34;价值?

感谢您的帮助

解决方案

我用这段代码解决了它

public class CommunicationMessageJSONSerializer : JsonConverter {

    /// <summary>
    /// Used to 
    /// </summary>
    /// <param name="objectType"></param>
    /// <returns></returns>
    public override bool CanConvert(Type objectType) {
        return typeof(CommunicationMessage).GetTypeInfo().IsAssignableFrom(objectType.GetTypeInfo());
    }

    /// <summary>
    /// Deserializes the JSON string
    /// </summary>
    /// <param name="reader"></param>
    /// <param name="objectType"></param>
    /// <param name="existingValue"></param>
    /// <param name="serializer"></param>
    /// <returns></returns>
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {

        // Load the JSON object from the reader
        JObject jsonObject = JObject.Load(reader);

        // Get the First Token
        JToken token = jsonObject.Children().First();

        // The deserialized message
        CommunicationMessage msg = ReadJSON(token);
        return msg;
    }

    /// <summary>
    /// This is the base method when deserializing a JSON string
    /// </summary>
    /// <param name="token"></param>
    /// <returns>The root CommunicationMessage</returns>
    private CommunicationMessage ReadJSON(JToken token) {

        CommunicationMessage root = new CommunicationMessage();

        if (token is JProperty) {
            if (token.First is JValue) {
                root.Key = ((JProperty)token).Name;
                root.Value = (string)((JProperty)token).Value;
            } else { 
                root.Key = ((JProperty)token).Name;

                foreach (JToken child in token.Children()) {
                    ReadRecursive(child, ref root);
                }
            }
        } else {
            foreach (JToken child in token.Children()) {
                ReadRecursive(child, ref root);
            }
        }
        return root;
    }

    /// <summary>
    /// This is the recursive method when deserializing a JSON string
    /// </summary>
    /// <param name="token"></param>
    /// <param name="root">The root of the coming messages</param>
    private void ReadRecursive(JToken token, ref CommunicationMessage root) {

        if (token is JProperty) {

            CommunicationMessage msg = new CommunicationMessage();

            if (token.First is JValue) {
                msg.Key = ((JProperty)token).Name;
                msg.Value = (string)((JProperty)token).Value;
            } else {
                msg.Key = ((JProperty)token).Name;

                foreach (JToken child in token.Children()) {
                    ReadRecursive(child, ref msg);
                }
            }
            root.Childs.Add(msg);
        } else {
            foreach (JToken child in token.Children()) {
                ReadRecursive(child, ref root);
            }
        }
    }

    /// <summary>
    /// Serializes a CommuicationMessage to a JSON string
    /// </summary>
    /// <param name="writer"></param>
    /// <param name="value"></param>
    /// <param name="serializer"></param>
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) {
        var msg = value as CommunicationMessage;
        WriteRecoursive(writer, msg, serializer);
    }

    /// <summary>
    /// This is the recursive method for serializing
    /// </summary>
    /// <param name="writer"></param>
    /// <param name="msg"></param>
    /// <param name="serializer"></param>
    private void WriteRecoursive(JsonWriter writer, CommunicationMessage msg, JsonSerializer serializer) {

        writer.WriteStartObject();
        writer.Formatting = Formatting.Indented;

        writer.WritePropertyName(msg.Key);

        if (msg.Childs.Count > 0) {
            writer.WriteStartArray();

            foreach (CommunicationMessage child in msg.Childs) {
                WriteRecoursive(writer, child, serializer);
            }

            writer.WriteEndArray();

        } else {
            writer.WriteValue(msg.Value);
        }

        writer.WriteEndObject();
    }
}

如果您有任何改进代码的想法,请告诉我。我会更新解决方案。

感谢大家的帮助

1 个答案:

答案 0 :(得分:2)

除了使用custom serialisation或实施ISerializable之外,您还可以执行以下操作。但请注意,此方法存在一个缺点,即所有属性都需要像这样包装,否则属性将不会被序列化。这种快速而脏的方法适用于小类,但如果要创建更复杂的类,最好实现ISerializable

 public class CommunicationMessage : Dictionary<string, object>       
 {
    //this "hack" exposes the "Child" as a List
    public List<CommunicationMessage> Childs
    {
        get {
            return (List<CommunicationMessage>)this["Childs"];
        }
        set
        {
            this["Childs"] = value;
        }
    }

    public CommunicationMessage()
    {
        this["Childs"] = new List<CommunicationMessage>();
    }
 }

用法:

var m = new CommunicationMessage();
m["mymessage"] = "This is a test";

输出应该看起来像

{
    "Childs": [],
    "mymessage": "This is a test"
}

替代ISerializable实现:

public class CommunicationMessage:ISerializable
{
    public String Key { get; set; }

    public String Value { get; set; }

    public List<CommunicationMessage> Childs { get; set; }

    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue(Key, Value);

        PropertyInfo[] pi=this.GetType().GetProperties();
        foreach(var p in pi)
        {
            if (p.Name == "Key" || p.Name == "Value")
                continue;
            info.AddValue(p.Name, p.GetValue(this));
        }
    }
}