反序列化具有抽象类型属性的对象

时间:2018-08-21 18:40:04

标签: c# asp.net-core .net-core json.net

在某些情况下,我需要反序列化json文件,但是一个属性有些不同。这是一个示例:

[
    {
        "NameProperty": "ex1",
        "OtherProperty":"example",
        "DifferentProperty": "here is a string value"
    },
    {
        "NameProperty": "ex1",
        "OtherProperty":"example",
        "DifferentProperty": ["here", "is", "an" "array"]
    },
    {
        "NameProperty": "ex1",
        "OtherProperty":"example",
        "DifferentProperty": 234 //number
    }
]

这是此类json的模型:

抽象类PropertyBase     {     }

class StringProperty : PropertyBase
{
    public string Value { get; set; }
}
class ArrayProperty : PropertyBase
{
    public IList<string> Value { get; set; }
}
class NumberProperty : PropertyBase
{
    public double Value { get; set; }
}


class ExampleModel
{
    public string NameProperty { get; set; }
    public string OtherProperty
    {
        get; set;
    }
    public PropertyBase DifferentProperty { get; set; }
}

然后我想将对象列表传递给控制器​​功能的asp.net核心,例如:

public IActionResult ExampleFunction([FromBody] List<ExampleModel> request){ }

这是一个问题,因为我知道如何反序列化派生类的列表,但是我不知道如何反序列化具有抽象类型的属性的对象。我想编写一个JsonConvert类,该类将传递给asp.net mvc配置。

2 个答案:

答案 0 :(得分:1)

我只是跳过了整个PropertyBase,为什么不为您的ExampleModel创建一个解析器来执行以下操作:

class ExampleModel
{
    public string NameProperty { get; set; }
    public string OtherProperty { get; set; }
    public object DifferentProperty { get; set; }

    public string DifferentPropertyString { get; set; }
    public string[] DifferentPropertyStringArray { get; set; }
    public int DifferentPropertyInt { get; set; }

    private void ResolveDifferentProperty()
    {
        // Try to resolve the DifferentProperty property with a converter or 
        //something similar into one of your three specific "DifferentProperty"'s?
    }
}

class Program
{
    public void Main(string[] args)
    {
        var model = JsonConvert.DeserializeObject<ExampleModel>(jsonData);
        model.ResolveDifferentProperty();
    }
}

为了知道哪个属性已解析,可以让ExampleModel包含DifferentPropertyEnum或其他属性,以便您知道解析中已填充了哪个属性。你明白了。

此外,请记住,在编译时将无法让您知道这实际上是什么样的属性。您无法使用 var 关键字或类似的关键字来访问它,因此,如果要经常使用该属性,则必须大量打开该属性。

您当然可以通过将DifferentProperty对象设置为动态对象(实际上是使用 dynamic 关键字)来绕过此操作。这不会生成编译器警告,但是如果您不小心就会使运行时崩溃。当然,它被认为更不安全,但是假设您的控制器只想将其存储在varchar数据库字段或其他内容中,那么我可能会选择动态的。

答案 1 :(得分:1)

您需要创建一个custom converter

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

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var token = JToken.Load(reader);
        var name = token["NameProperty"].ToString();
        PropertyBase prop = null;
        // for example, it is up to you how you
        // create an instance of PropertyBase
        switch (name)
        {
            case "string" : prop = new StringProperty();
                break;
            case "number" : prop = new NumberProperty();
                break;
            case "array" : prop = new ArrayProperty();
                break;
        }

        var ex = new ExampleModel
        {
            DifferentProperty = prop
        };
        serializer.Populate(reader, ex);
        return ex;
    }

    public override bool CanConvert(Type objectType)
    {
        return typeof(ExampleModel) == objectType;
    }
}

[JsonConverter(typeof(PropertyConverter))]
class ExampleModel
{
    public string NameProperty { get; set; }
    public string OtherProperty
    {
        get; set;
    }
    public PropertyBase DifferentProperty { get; set; }
}

class Program
{
    public void Main(string[] args)
    {
        var model = JsonConvert.DeserializeObject<ExampleModel>(jsonData);
    }
}