【发布时间】:2014-02-17 10:24:41
【问题描述】:
我有一个JsonConverter,根据特定于实例的标志,需要
- 运行自定义序列化逻辑
- 运行默认的 Json.NET 序列化逻辑
如何从JsonConverter 运行默认的 Json.NET 序列化逻辑?
谢谢
【问题讨论】:
标签: c# serialization json.net
我有一个JsonConverter,根据特定于实例的标志,需要
如何从JsonConverter 运行默认的 Json.NET 序列化逻辑?
谢谢
【问题讨论】:
标签: c# serialization json.net
这是一个例子。假设您要序列化的类如下所示:
class Foo
{
public bool IsSpecial { get; set; }
public string A { get; set; }
public string B { get; set; }
public string C { get; set; }
}
IsSpecial 标志用于控制我们是在转换器中做一些特殊的事情还是让事情自然地序列化。你可以这样写你的转换器:
class FooConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(Foo).IsAssignableFrom(objectType);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
Foo foo = (Foo)value;
JObject jo;
if (foo.IsSpecial)
{
// special serialization logic based on instance-specific flag
jo = new JObject();
jo.Add("names", string.Join(", ", new string[] { foo.A, foo.B, foo.C }));
}
else
{
// normal serialization
jo = JObject.FromObject(foo);
}
jo.WriteTo(writer);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
然后,要使用转换器,请将其实例传递给 SerializeObject 方法(例如在设置中)。 (不要用JsonConverter 属性装饰目标类,否则在序列化时会导致无限递归循环。)
class Program
{
static void Main(string[] args)
{
List<Foo> foos = new List<Foo>
{
new Foo
{
A = "Moe",
B = "Larry",
C = "Curly",
IsSpecial = false
},
new Foo
{
A = "Huey",
B = "Dewey",
C = "Louie",
IsSpecial = true
},
};
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.Converters.Add(new FooConverter());
settings.Formatting = Formatting.Indented;
string json = JsonConvert.SerializeObject(foos, settings);
Console.WriteLine(json);
}
}
输出:
[
{
"IsSpecial": false,
"A": "Moe",
"B": "Larry",
"C": "Curly"
},
{
"names": "Huey, Dewey, Louie"
}
]
【讨论】:
FooConverter 也需要包含在序列化过程中。然后这会导致“正常”序列化再次通过FooConverter,使用IsSpecial = false。换句话说,问题在于序列化过程中遇到的字段与直接传递到JsonConvert.Serialize 的对象不同。一个(非最佳)解决方案是要求所有字段引用都使用[JsonConverter] 引用进行注释。
JsonSerializer 传入JObject.FromObject 来完成。例如:var jo = JObject.FromObject(value, JsonSerializer.CreateDefault(new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All }));
您可以更改 CanWrite 属性以禁用自定义序列化程序。如果对象可以包含相同类型的子对象或者您在多个线程中进行序列化,这将无法正常工作。
class FooConverter : JsonConverter
{
bool _canWrite = true;
public override bool CanWrite
{
get { return _canWrite;}
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
Foo foo = (Foo)value;
JObject jo;
if (foo.IsSpecial)
{
// special serialization logic based on instance-specific flag
jo = new JObject();
jo.Add("names", string.Join(", ", new string[] { foo.A, foo.B, foo.C }));
}
else
{
// normal serialization
_canWrite = false;
jo = JObject.FromObject(foo);
_canWrite = true;
}
jo.WriteTo(writer);
}
}
【讨论】:
CanRead 和 CanWrite 以防止递归正在工作非常适合我。 -- 不过,我使用serializer.Serialize(writer, value); 写入值,我建议将值设置回finally 块中的原始值,这样它就不会陷入奇怪的状态。