如果重写ToString,JSON.NET序列化

时间:2013-09-26 18:46:01

标签: c# json serialization json.net

我有一组复杂的业务对象,我想序列化到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()的对象,我宁愿避免引入特殊属性等。

4 个答案:

答案 0 :(得分:1)

你可能正在测试这个错误。我刚刚在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"}

答案 1 :(得分:1)

您的实际类是否可能附加了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
    {
    }
}

答案 2 :(得分:1)

我怀疑您使用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 :(得分:0)

使用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