在json反序列化期间确定类型

时间:2016-07-31 01:29:53

标签: c# json serialization json.net

我正在研究一种协议,其中接收器将接收某些指定自定义类型的json消息(当前为5,但可能为10-20)。我正在努力想出一个最佳/快速的解决方案,它将自动反序列化json并返回正确类型的对象。

示例:

public class MessageA
{
    public string Message;
} 

public class MessageB
{
    public int value;
}

public class MessageC
{
    public string ValueA;
    public string ValueB;
}

理想情况下,该方法应该像

 Object Deserialize(string json);

并且它将返回三种消息类型之一OR null - 如果存在解析错误/ json与任何预定义类型都不匹配。

更新:我可以控制发送方/接收方以及协议设计。

3 个答案:

答案 0 :(得分:4)

如果消息可以指定其类型,将会很有帮助。否则你必须从某个财产或其他财产推断它。

序列化时可以使用消息包装类,如下所示:

public class MessageWrapper<T>
{
    public string MessageType { get { return typeof(T).FullName; } }
    public T Message { get; set; }
}

因此,如果您的班级Name具有FirstLast属性,则可以将其序列化为:

var nameMessage = new MessageWrapper<Name>();
nameMessage.Message = new Name {First="Bob", Last = "Smith"};
var serialized = JsonConvert.SerializeObject(nameMessage);

序列化的JSON是

{"MessageType":"YourAssembly.Name","Message":{"First":"Bob","Last":"Smith"}}

反序列化时,首先将JSON反序列化为此类型:

public class MessageWrapper
{
    public string MessageType { get; set; }
    public object Message { get; set; }
}

var deserialized = JsonConvert.DeserializeObject<MessageWrapper>(serialized);

MessageType属性中提取消息类型。

var messageType = Type.GetType(deserialized.MessageType);

现在您知道了类型,您可以反序列化Message属性。

var message = JsonConvert.DeserializeObject(
    Convert.ToString(deserialized.Message), messageType);

messageobject,但您可以将其转换为Name或其实际所在的类别。

答案 1 :(得分:1)

function htmlEntities(str) {
    return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
}

Json 示例:

var log = JsonConvert.DeserializeObject<Log>(File.ReadAllText("log.example.json");

public class Log
{
    [JsonConverter(typeof(MessageConverter))]
    public object[] Messages { get; set; }
}


public class MessageA
{
    public string Message;
}
public class MessageB
{
    public int value;
}
public class MessageC
{
    public string ValueA;
    public string ValueB;
}

public class MessageConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return true;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        object ReadMessage(JObject jobject)
        {
            if (jobject.Property("Message") != null)
                return jobject.ToObject<MessageA>(serializer);
            if (jobject.Property("value") != null)
                return jobject.ToObject<MessageB>(serializer);
            if (jobject.Property("ValueA") != null)
                return jobject.ToObject<MessageC>(serializer);
            throw new Exception("Type is not recognized");
        }

        var jarray = JArray.Load(reader);
        return jarray.Select(jitem => ReadMessage((JObject)jitem)).ToArray();
    }


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

答案 2 :(得分:0)

希望您熟悉工厂模式,您可以使用工厂并在json中包含“Type”属性,让我们称之为_t

您可以自己解析json字符串并找到_t属性的值,将其反序列化为dynamic并获取jsonObj._t或只有一个简单的class _t字段仅用于最初将json反序列化。

然后,您可以将表示C#类型的string传递给工厂,并为Type获取json反序列化器。

然后,您可以分别添加和处理所有传出和传入呼叫,以便将来很容易添加新类型,只需添加和注册您需要的序列化程序/解串器_t与工厂合作。