我可以将json解析为字符串或其他具体类型作为对象吗?

时间:2015-10-12 12:12:46

标签: c# json json.net

我希望object类型的属性可以是stringTemplate类型。

是否可以告诉Json.NET将某些内容解析为几种指定类型之一?

class MyClass
{
    public object Template { get; set; }
}

其中Template = "TemplateName"

{
    "Template": "TemplateName"
}

Template = new Template()

{
    "Template": { "Name": "OtherTamplate", ... }
}

更新:

我试图关注@ krillgar'建议并创建自定义JsonConverter但不幸的是CanConvert方法只接收目标类型,在本例中为object。这些信息不足以告诉它可以反序列化(如果我有其他object属性)。我想我毕竟需要它是Template或创建像TemplateReference之类的派生类型:

class myconverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override bool CanConvert(Type objectType)
    {
        // objectType = typeof(object)
        throw new NotImplementedException();
    }
}

Configuration = JsonConvert.DeserializeObject<MyClass>(text, new myconverter());

声明

此问题曾被视为How to deserialize a JSON property that can be two different data types using Json.NET的副本。因为在撰写我的问题时,我不知道已经有类似的问题,我想澄清它们之间的区别,以防止它在将来被关闭:

另一个问题是如何将不同的值反序列化为具体的类型,而我的是将不同的值反序列化为对象。在第一次看起来似乎是相同的,因为在两个示例中,只有属性的类型不同,但它对整个应用程序设计有巨大影响。对我来说很重要的是,我可以使用对象来存储不同的专用类型,而不是一种具有多种职责的类型。

3 个答案:

答案 0 :(得分:2)

使用自定义JsonConverter可以解决此问题。这是适用于这种情况的通用版本:

class ObjectOrStringConverter<T> : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        // CanConvert is not called when the [JsonConverter] attribute is used
        return false;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JToken token = JToken.Load(reader);
        if (token.Type == JTokenType.Object)
        {
            return token.ToObject<T>(serializer);
        }
        return token.ToString();
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        serializer.Serialize(writer, value);
    }
}

要使用转换器,您只需向类中的属性添加[JsonConverter]属性,该属性可以是字符串或对象。泛型类型参数必须与您期望的非字符串对象的类型匹配。

class MyClass
{
    [JsonConverter(typeof(ObjectOrStringConverter<Template>))]
    public object Template { get; set; }
}

下面是转换器运行的演示:

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("--- first run ---");

        string json = @"
        {
            ""Template"": ""TemplateName""
        }";

        DeserializeAndDump(json);

        Console.WriteLine("--- second run ---");

        json = @"
        {
            ""Template"": { ""Name"": ""OtherTemplate"" }
        }";

        DeserializeAndDump(json);
    }

    static void DeserializeAndDump(string json)
    {
        MyClass obj = JsonConvert.DeserializeObject<MyClass>(json);
        if (obj.Template == null)
        {
            Console.WriteLine("Template property is null");
        }
        else
        {
            Console.WriteLine("Template property is a " + obj.Template.GetType().Name);

            string name = "(unknown)";
            if (obj.Template is Template) name = ((Template)obj.Template).Name;
            else if (obj.Template is string) name = (string)obj.Template;

            Console.WriteLine("Template name is \"" + name + "\"");
        }
        Console.WriteLine();
    }
}

class Template
{
    public string Name { get; set; }
}

这是上面的输出:

--- first run ---
Template property is a String
Template name is "TemplateName"

--- second run ---
Template property is a Template
Template name is "OtherTemplate"

小提琴:https://dotnetfiddle.net/Lw3RaN

答案 1 :(得分:1)

我不知道你是否可以这样做,但你可以采取另一种方式。更改你的&#34;模板&#34;属性为Template而不是object,并使用Template类的自定义属性来了解您要将其序列化为Template或{{1 }}

string

答案 2 :(得分:0)

如果您有一个属性,哪个类型是类似抽象类型的对象,那么在反序列化时,您可以通过序列化某个地方也知道该序列化的特定类型,也就是该特定类型的名称。 所以你的json应该是这样的:

{     &#34; MyClass&#34;:{         &#34;模板&#34;:&#34;某些名称&#34;,         &#34;输入&#34;:&#34; System.String&#34;     } }

这种反序列化方法可以在序列化之前检查该属性的类型(在本例中为String)

确定类型的另一种方法是检查json结构,如下所示: C#: Deserializing JSON when one field can be different types