我有一组复杂的业务对象,我想将其序列化为 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(( 的对象,因此我宁愿避免引入特殊属性等。
你的实际类是否有可能附加了一个TypeConverterAttribute?我刚刚遇到了完全相同的问题,并发现TypeConverterAttribute导致了这种情况。在这种情况下,这可能会有所帮助(至少它对我有用(。
这是非常糟糕的,因为您可能会无意中破坏程序(通过简单地添加一个类型转换器,也许是为了在 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
{
}
}
你可能测试错了。我刚刚在 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"}
我怀疑您正在使用MyClass
作为字典或哈希表中的键?
林克帕德示例:
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 中的键。
要解决此问题,请更改模型或实现类型转换器。如果你的对象足够简单,你可以ConvertTo
,ConvertFrom
简单地按给定顺序读取和写入参数。
[编辑]
事实证明,这比我预期的要简单。这是我的 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; }
使用 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://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonserializer?view=netcore-3.1
上下文:https://youtu.be/JfnTG955cuk?t=406