代码之家  ›  专栏  ›  技术社区  ›  Jaume

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

  •  0
  • Jaume  · 技术社区  · 8 年前

    我有一个案例需要对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核心A控制器函数,例如:

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

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

    2 回复  |  直到 8 年前
        1
  •  1
  •   Zysce myrtle303    8 年前

    您需要创建一个 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
  •  1
  •   Philzax    8 年前

    我将跳过整个PropertyBase,为什么不为您的示例模型创建一个这样的解析器:

    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 关键字或类似的东西,所以如果你要经常使用的话,你必须经常打开这个属性。

    当然,您可以通过使不同的属性对象成为一个动态对象(字面上是 动态 关键字)。这不会生成编译器警告,但如果不小心,它会使运行时崩溃。当然,它被认为是更不安全的,但是假设您的控制器只想将它存储在varchar数据库字段或其他地方,那么我可能会使用动态的。