【问题标题】:Deserialize an object with property of abstract type反序列化具有抽象类型属性的对象
【发布时间】:2018-08-21 18:40:03
【问题描述】:

我有一种情况,我需要反序列化一个 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 config。

【问题讨论】:

  • 因为抽象类没有实例化

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


【解决方案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);
    }
}

【讨论】:

  • 谢谢,这就是我想要的! :) 我步入正轨,但你启发了我 :)
【解决方案2】:

我只是跳过整个 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 数据库字段或其他东西中,那么我可能会选择动态。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-14
    • 2016-07-07
    • 2021-12-09
    • 1970-01-01
    相关资源
    最近更新 更多