假设我有以下内容(我的实际代码的非常简化的版本;假设Wrapper
和C
有更多未显示的成员(:
interface I { }
class C : I
{
public string Name { get; set; }
}
class Wrapper
{
public I Instance { get; set; }
}
class Program
{
static void Main(string[] args)
{
Wrapper wrapper = new Wrapper
{
Instance = new C { Name = "Test" }
};
JsonSerializerSettings settings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Auto
};
Console.WriteLine(JsonConvert.SerializeObject(wrapper, Formatting.Indented, settings));
}
}
输出将包括 Instance 的类型信息,因为实际类型与其声明的类型不同,正如预期的那样:
{
"Instance": {
"$type": "ConsoleApplication.C, ConsoleApplication",
"Name": "Test"
}
}
相反,假设我使用自定义JsonConverter
来Wrapper
:
class WrapperConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(Wrapper);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
Wrapper wrapper = (Wrapper)value;
JObject root = new JObject();
JObject instance = JObject.FromObject(wrapper.Instance);
root.Add("Instance", instance);
root.WriteTo(writer);
}
}
这不再输出实例的类型信息:
{
"Instance": {
"Name": "Test"
}
}
在WrapperConverter.WriteJson
中手动构造JObject
时,如何强制包含Instance
的类型信息?
为了发出"$type"
TypeNameHandling.Auto
根对象的信息,您需要使用具有预期根类型参数的JsonSerializer.Serialize()
重载之一:
-
JsonSerializer.Serialize(JsonWriter, Object, Type)
-
JsonSerializer.Serialize(TextWriter, Object, Type)
但是,正如您已经注意到的,没有允许传递预期根类型的JObject.FromObject()
重载。 因此,您将使用JTokenWriter
手动构建JObject
:
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
Wrapper wrapper = (Wrapper)value;
JObject root = new JObject();
using (var tokenWriter = new JTokenWriter())
{
serializer.Serialize(tokenWriter, wrapper.Instance, typeof(object));
root.Add("Instance", tokenWriter.Token);
}
root.WriteTo(writer);
}
您还可以通过跳过中间JObject
表示形式来提高性能:
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
Wrapper wrapper = (Wrapper)value;
writer.WriteStartObject();
writer.WritePropertyName("Instance");
serializer.Serialize(writer, wrapper.Instance, typeof(object));
writer.WriteEndObject();
}
如果将WriteJson
修改为:
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var wrapper = (Wrapper)value;
var root = new JObject();
var instance = JObject.FromObject(wrapper.Instance, new JsonSerializer
{
TypeNameHandling = TypeNameHandling.Objects
});
root.Add("Instance", instance);
root.WriteTo(writer);
}
它还将输出 $type
属性。