如何获取JObject.FromObject(对象)以包含类型信息?

时间:2016-02-14 20:54:24

标签: c# json.net

假设我有以下内容(我的实际代码的一个非常简化的版本;假设WrapperC有更多的成员没有显示):

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的类型信息:

{
  "Instance": {
    "Name": "Test"
  }
}

Instance中手动构建JObject时,如何强制包含WrapperConverter.WriteJson的类型信息?

2 个答案:

答案 0 :(得分:2)

如果您将meta.getSQLStatementsString();修改为:

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); } 属性。

答案 1 :(得分:1)

为了使用"$type"为根对象发出TypeNameHandling.Auto信息,您需要使用JsonSerializer.Serialize()的一个重载,该重载具有预期的参数 root 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();
    }