【问题标题】:JSON.NET serialization if override ToStringJSON.NET 序列化(如果覆盖 ToString)
【发布时间】:2013-10-02 21:26:41
【问题描述】:

我有一组复杂的业务对象,我想将它们序列化为 Json 以在 Web 服务中使用。我目前正在使用 DataContractJsonSerializer 来生成 Json,但由于默认的 XmlReader 无法处理 Base64 字符串,因此它在反序列化方面犹豫不决。

在阅读了许多对 Json.Net 的正面评价后,我决定试一试。令人惊讶的是,如果业务对象覆盖 ToString() 方法,最简单的情况会产生错误输出。它不生成 JSON,而是简单地发出字符串值。

例如,以下语句只产生一个字符串,因为序列化程序似乎将对象视为一个简单的字符串。

public class MyClass {
    public string Title{get;set;}
    public override ToString(){ return Title; }
    public string ToJson(){ 
        return JsonConvert.SerializeObject(this); 
    }
}

我得到的不是 json 格式的输出,而是标题字符串。我是否必须以某种特殊方式标记对象以避免这种情况?由于业务对象层次结构包含许多覆盖 ToString() 的对象,因此我宁愿避免引入特殊属性等。

【问题讨论】:

  • 您的代码工作正常,只有一件事在ToString 方法中调用ToJson
  • 我得到了同样的行为。你有没有发现发生了什么?

标签: c# json serialization json.net


【解决方案1】:

使用 System.Text.Json 中的 JsonSerializer 序列化类。像这样:

using System.Text.Json;
...


    public class Foo{
    Public String Title {get;set;}
    
        public override ToString(){
        return JsonSerializer.Serialize<Foo>(this);
        }
    }

文档: https://docs.microsoft.com/en-us/dotnet/api/system.text.json.jsonserializer?view=netcore-3.1

上下文: https://youtu.be/JfnTG955cuk?t=406

【讨论】:

    【解决方案2】:

    我怀疑您使用MyClass 作为字典或哈希表中的键?

    Linqpad 示例:

    void Main()
    {
        object thing = new Dictionary<MyClass, MyClass>() { 
            { 
                new MyClass { Title = "hi" }, new MyClass { Title = "bye" } 
            }
        };  
        JsonConvert.SerializeObject(thing).Dump();
    }
    
    public class MyClass
    {
        public string Title { get; set; }
        public override string ToString() { return "BROKEN"; }
    }
    

    输出:

    {"BROKEN":{"Title":"bye"}}
    

    这是预期的行为,因为无法将复杂对象表示为 json 中的键。

    要解决此问题,请更改您的模型或实施TypeConverter。 如果您的对象足够简单,您可以让ConvertToConvertFrom 按给定顺序简单地读取和写入参数。

    [编辑]

    事实证明这比我预期的要简单。这是我的 JsonConverter 解决方案。

    public class ObjectKeyDictionaryTypeConverter<T1, T2> : JsonConverter<Dictionary<T1, T2>>
    {   
        public override void WriteJson(JsonWriter writer, Dictionary<T1, T2> value, JsonSerializer serializer)
        {
            serializer.Serialize(writer, value.ToArray());
        }
    
        public override Dictionary<T1, T2> ReadJson(JsonReader reader, Type objectType, Dictionary<T1, T2> existingValue, bool hasExistingValue, JsonSerializer serializer)
        {
            var items = serializer.Deserialize(reader) as KeyValuePair<T1,T2>[];
            return items?.ToDictionary(a => a.Key, a => a.Value);
        }
    }
    

    用法:

    [JsonConverter(typeof(ObjectKeyDictionaryTypeConverter<ICriteria, Results>))]
    public Dictionary<ICriteria, Results> SearchesAndResults { get; set; }
    

    【讨论】:

      【解决方案3】:

      你的实际类是否有可能附加了一个 TypeConverterAttribute ?我刚刚遇到了完全相同的问题,发现是 TypeConverterAttribute 造成的。在这种情况下,this 可能会有所帮助(至少对我有用)。

      这非常糟糕,因为您可能会无意中破坏您的程序(通过简单地添加一个 TypeConverter 可能用于在 PropertyGrid 中显示对象)而不会收到编译器警告...

      using Newtonsoft.Json;
      using System;
      using System.ComponentModel;
      
      namespace ConsoleApplication5
      {
          class Program
          {
              static void Main(string[] args)
              {
                  var with = new WithTypeConverter() { Bla = 12, Blub = "With" };
                  var without = new WithoutTypeConverter() { Bla = 12, Blub = "Without" };
      
                  Console.WriteLine(with);
                  Console.WriteLine(JsonConvert.SerializeObject(with));
      
                  Console.WriteLine(without);
                  Console.WriteLine(JsonConvert.SerializeObject(without));
                  Console.ReadKey();
              }
          }
      
          public class baseClass
          {
              public int Bla { get; set; }
              public string Blub { get; set; }
      
              public override string ToString()
              {
                  return String.Format("{0}: {1}", this.GetType().Name, Blub);
              }
          }
      
          [TypeConverter(typeof(ExpandableObjectConverter))]
          public class WithTypeConverter : baseClass
          {
          }
      
          public class WithoutTypeConverter : baseClass
          {
          }
      }
      

      【讨论】:

        【解决方案4】:

        你可能测试错了。我刚刚在 LINQPad 中运行了以下代码:

        void Main()
        {
            new MyClass{Title = "hi"}.ToJson().Dump();
        }
        
        // Define other methods and classes here
        public class MyClass {
            public string Title{get;set;}
            public override string ToString(){ return Title; }
            public string ToJson(){ 
                return JsonConvert.SerializeObject(this); 
            }
        }
        

        输出:

        {"Title":"hi"}
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2023-03-06
          • 1970-01-01
          • 1970-01-01
          • 2020-09-14
          • 2012-02-05
          • 1970-01-01
          • 2020-03-09
          相关资源
          最近更新 更多