簡體   English   中英

我可以將json解析為字符串或其他具體類型作為對象嗎?

[英]Can I parse json either into a string or another concrete type as object?

我想擁有類型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());

放棄

此問題曾作為如何使用Json.NET反序列化可能是兩種不同數據類型的JSON屬性的副本而關閉。 因為在撰寫我的問題時,我不知道已經有類似的問題,我想澄清它們之間的區別,以防止它在將來被關閉:

另一個問題是如何將不同的值反序列化為具體類型,而我的是將不同的值反序列化為對象 在第一次看起來似乎是相同的,因為在兩個示例中,只有屬性的類型不同,但它對整個應用程序設計有巨大影響。 對我來說很重要的是,我可以使用一個對象來存儲不同的專用類型,而不是一種具有多種職責的類型。

使用自定義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

我不知道你是否可以這樣做,但你可以采取另一種方式。 將“Template”屬性更改為Template而不是object並使用Template類的自定義屬性來了解要將其序列化為Templatestring

class MyClass
{
    [JsonConverter(typeof(TemplateConverter))]
    public Template Template { get; set; }
}

class Template
{
    /* Your Template class */

    public Type TypeToSerializeInto { get; private set; }
}

public class TemplateConverter : JsonConverter
{
    public override bool CanConvert(Type objectType) 
    { 
        return objectType == typeof(Template);
    }

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

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
        Template val = value as Template;

        writer.WriteStartObject();
        writer.WritePropertyName("Template");

        if (val.TypeToSerializeInto == typeof(Template))
            serializer.Serialize(writer, val);
        else if (val.TypeToSerializeInto == typeof(string))
            serializer.Serialize(writer, val.Name);

        writer.WriteEndObject();
    }
}

如果您有一個屬性,哪個類型是類似抽象類型的對象,那么在反序列化時,您可以通過序列化某個特定類型的名稱來了解序列化的特定類型。 所以你的json應該是這樣的:

{“MyClass”:{“Template”:“some name”,“type”:“System.String”}}

這種方式在反序列化時,您可以在序列化之前檢查該屬性的類型(在本例中為String)

確定類型的另一種方法是檢查json結構,如下所示: C#:當一個字段可以是不同類型時反序列化JSON

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM