【问题标题】:Storing original JSON string in deserialised JSON.NET objects将原始 JSON 字符串存储在反序列化的 JSON.NET 对象中
【发布时间】:2018-03-27 15:22:05
【问题描述】:

这基本上是问题Newtonsoft Object → Get JSON string 的后续。

我有一个看起来像这样的对象:

[JsonConverter(typeof(MessageConverter))]
public class Message
{
    public Message(string original)
    {
        this.Original = original;
    }

    public string Type { get; set; }

    public string Original { get; set; }
}

我的要求是在初始化时将原始 JSON 字符串存储为对象的一部分。我已经能够(部分)使用自定义JsonConverter 成功实现这一点,然后基本上在JsonConverter 中执行类似的操作:

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
    if (reader.TokenType == Newtonsoft.Json.JsonToken.Null)
        return null;

    JObject obj = JObject.Load(reader);
    return new Message(obj.ToString(Formatting.None))
    {
        Type = obj["type"].ToString()
    };
}

但是我遇到的问题是当我尝试使用类似的东西从Message 继承时

public class CustomMessage : Message
{
    public string Prop1 { get; set; }
}

由于显而易见的原因,我的代码失败了,因为它试图返回一个新的Message() 而不是一个新的CustomMessage()

没有用我的所有子类型实现一个大的 if 语句并使用 JObject["prop"].ToObject<T>() 之类的东西手动绑定,我如何才能成功填充 Original 属性,同时仍然使用默认反序列化绑定我的所有子类型值?

注意:这样做的原因是因为原始消息可能包含实际上没有被绑定的数据,所以我不能只添加一个按原样序列化对象的属性。

【问题讨论】:

标签: c# json json.net deserialization


【解决方案1】:

我将问题悬而未决,希望有人提出更好的答案,但我暂时使用以下解决方案来解决我的问题。

public static class MessageExtensions
{
    public static T Deserialize<T>(this string message) where T : Message
    {
        T instance = Activator.CreateInstance<T>();
        instance.Original = message;
        JsonConvert.PopulateObject(message, instance);
        return instance;
    }
}

【讨论】:

    【解决方案2】:

    以下解决方案有效

    您可以做的一件事是用通用JsonConverter 属性装饰每个子类。

    [JsonConverter(typeof(MessageConverter<Message>))]
    public class Message
    {
        public Message(string original)
        {
            this.Original = original;
        }
    
        public string Type { get; set; }
    
        public string Original { get; set; }
    }
    [JsonConverter(typeof(MessageConverter<CustomMessage>))]
    public class CustomMessage : Message
    {
        public CustomMessage(string original) : base(original)
        {
        }
        public string Prop1 { get; set; }
    }
    

    公共类 MessageConverter : JsonConverter where T : Message { public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { 抛出新的 NotImplementedException(); }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            if (reader.TokenType == Newtonsoft.Json.JsonToken.Null)
                return null;
    
            JObject obj = JObject.Load(reader);
            var customObject = JsonConvert.DeserializeObject<T>(obj.ToString(), new JsonSerializerSettings 
                            {
                                ContractResolver = new CustomContractResolver()
                            });
            customObject.Original = obj.ToString();
                return customObject;
        }
    
        public override bool CanConvert(Type objectType)
        {
            throw new NotImplementedException();
        }
    }
    
    //This will remove our declared Converter
    public class CustomContractResolver : DefaultContractResolver
    {
        protected override JsonConverter ResolveContractConverter (Type objectType)
        {
            return null;
        }
    }
    

    然后您可以对所有子类使用相同的序列化程序

    CustomMessage x = JsonConvert.DeserializeObject<CustomMessage>("{\"type\":\"Test\",\"Prop1\":\"Prop1\"}");
     Message y = JsonConvert.DeserializeObject<Message>("{\"type\":\"Test\"}");
    

    这是输出屏幕截图

    【讨论】:

    • 虽然这是在正确的轨道上。那是行不通的,因为其余的对象属性不会被反序列化。尝试将您的示例代码更改为 "{\"type\":\"Test\", \"Prop1\":\"Test2\"}" 你会看到问题。
    • @MaximGershkovich 我想我找到了解决方案 :-) 请检查更新后的答案
    • 是的,感谢您的建议,虽然我赞成您的解决方案,因为它在技术上解决了问题。我不确定我是否比我更喜欢您的解决方案。答案可能是它不值得努力。我将把问题留待更长时间,看看是否有其他人提出更好的解决方案。
    猜你喜欢
    • 1970-01-01
    • 2013-07-09
    • 1970-01-01
    • 2020-07-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多