【问题标题】:JSON Deserialization with an array of polymorphic objects具有多态对象数组的 JSON 反序列化
【发布时间】:2011-10-29 00:37:58
【问题描述】:

我遇到了涉及多态对象数组的 JSON 反序列化问题。我已经尝试过记录在herehere 的序列化解决方案,它们非常适合序列化,但都在反序列化时崩溃了。

我的班级结构如下:

可识别

[DataContract(IsReference=true)]
public abstract class IDable<T> {

    [DataMember]
    public T ID { get; set; }
}

观察组

[DataContract(IsReference=true)]
[KnownType(typeof(DescriptiveObservation))]
[KnownType(typeof(NoteObservation))]
[KnownType(typeof(NumericObservation))]
[KnownType(typeof(ScoredObservation))]
public class ObservationGroup : IDable<int> {

    [DataMember]
    public string Title { get; set; }

    [DataMember]
    public List<Observation> Observations { get; set; }

    [OnDeserializing]
    void OnDeserializing(StreamingContext context)
    {
        init();
    }

    public ObservationGroup()  {
        init();
    }

    private void init()
    {
        Observations = new List<Observation>();
        ObservationRecords = new List<ObservationRecord>();
    }

}

描述性观察

[DataContract(IsReference = true)]
public class DescriptiveObservation : Observation
{

    protected override ObservationType GetObservationType()
    {
        return ObservationType.Descriptive;
    }
}

注意观察

[DataContract(IsReference = true)]
public class NoteObservation : Observation
{
    protected override ObservationType GetObservationType()
    {
        return ObservationType.Note;
    }
}

数值观察

[DataContract(IsReference = true)]
public class NumericObservation : Observation
{
    [DataMember]
    public double ConstraintMaximum { get; set; }
    [DataMember]
    public double ConstraintMinimum { get; set; }
    [DataMember]
    public int PrecisionMaximum { get; set; }
    [DataMember]
    public int PrecisionMinimum { get; set; }
    [DataMember]
    public string UnitType { get; set; }

    protected override ObservationType GetObservationType()
    {
        return ObservationType.Numeric;
    }
}

评分观察

[DataContract(IsReference = true)]
public class ScoredObservation : Observation {
    [DataMember]
    public int Value { get; set; }

    protected override ObservationType GetObservationType() {
        return ObservationType.Scored;
    }
}

我对使用内置 JavaScriptSerializer 或 Newtonsoft JSON 库持公正态度。

序列化代码

var settings = new Newtonsoft.Json.JsonSerializerSettings();
settings.TypeNameHandling = Newtonsoft.Json.TypeNameHandling.Objects;

Newtonsoft.Json.JsonConvert.SerializeObject(AnInitializedScoresheet, Newtonsoft.Json.Formatting.None, settings);

反序列化代码

return Newtonsoft.Json.JsonConvert.DeserializeObject(returnedStringFromClient, typeof(Scoresheet));
//Scoresheet contains a list of observationgroups

我得到的错误是

“无法创建 ProjectXCommon.DataStores.Observation 类型的实例。类型是接口或抽象类,无法实例化。”

任何帮助将不胜感激!

【问题讨论】:

  • 我很确定它与您的 List&lt;Observation&gt; 相关,反序列化程序正在尝试实例化 Observation 的类型,而不是它实际的特定类型。使用 Newtonsoft,您可以通过添加您自己的转换器来覆盖部分反序列化(这里是一个示例 gist.github.com/1140171)我不确定这对您有多大帮助,因为我不完全确定但相当肯定就是这种情况。 :)
  • json 样本会有帮助

标签: c# json asp.net-mvc-3 json.net


【解决方案1】:

使用这个JsonKnownTypes,类似的方法:

[JsonConverter(typeof(JsonKnownTypesConverter<BaseClass>))]
[JsonKnownType(typeof(Base), "base")]
[JsonKnownType(typeof(Derived), "derived")]
public class Base
{
    public string Name;
}
public class Derived : Base
{
    public string Something;
}

现在,当您在 json 中序列化对象时,将添加 "$type""base""derived" 值,它将用于反序列化

序列化列表示例:

[
    {"Name":"some name", "$type":"base"},
    {"Name":"some name", "Something":"something", "$type":"derived"}
]

【讨论】:

    【解决方案2】:

    您没有在反序列化时添加任何设置。您需要将TypeNameHandling 设置为ObjectAll 来应用设置。

    像这样:

    JsonConvert.DeserializeObject(
        returnedStringFromClient, 
        typeof(Scoresheet), 
        new JsonSerializerSettings 
        { 
            TypeNameHandling = TypeNameHandling.Objects 
        });
    

    文档:TypeNameHandling setting

    【讨论】:

    • 噢!对于仍在使用 .NET JavascriptSerializer 的用户,您还可以使用 new JavaScriptSerializer(new System.Web.Script.Serialization.SimpleTypeResolver()).Deserialize(returnedStringFromClient, typeof(Scoresheet));
    • 从 RavenDB build 499(RavenDB 使用 JSON.NET)开始,当使用 T 是接口的通用 List 时,您需要添加 [JsonProperty(TypeNameHandling = TypeNameHandling.All)] 属性。这修复了异常“无法创建类型为'您的接口'类型的实例类型是接口或抽象类并且无法实例化。”
    猜你喜欢
    • 2011-07-08
    • 1970-01-01
    • 1970-01-01
    • 2021-02-11
    • 2020-07-27
    • 1970-01-01
    • 2015-06-11
    • 2020-12-02
    • 2013-05-07
    相关资源
    最近更新 更多