使用多态对象数组进行JSON反序列化

28
我在JSON反序列化涉及多态对象数组方面遇到了问题。我尝试了文档这里这里中的序列化解决方案,它们对于序列化工作得很好,但是在反序列化时都会出现问题。
我的类结构如下:

IDable

[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;
    }
}

NoteObservation

[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;
    }
}

得分观察(ScoredObservation)
[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<Observation> 有关,反序列化程序试图实例化一个 Observation 类型,而不是它实际上的特定类型。使用Newtonsoft,您可以通过添加自己的转换器来覆盖反序列化的某些部分(这里是一个示例 https://gist.github.com/1140171)。我不确定这会对您有多大帮助,因为我不是完全确定,但相当确定这就是情况。 :) - Buildstarted
JSON示例将非常有帮助。 - Frank
2个回答

30

在反序列化期间,您没有添加任何设置。您需要应用设置,其中TypeNameHandling设置为ObjectAll

像这样:

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

文档: TypeNameHandling设置


糟糕!对于仍在使用 .NET JavascriptSerializer 的人,你也可以使用以下代码:new JavaScriptSerializer(new System.Web.Script.Serialization.SimpleTypeResolver()).Deserialize(returnedStringFromClient, typeof(Scoresheet)); - Chainlink
1
从RavenDB构建499开始(RavenDB使用JSON.NET),当使用一个T为接口的通用列表时,您需要添加[JsonProperty(TypeNameHandling = TypeNameHandling.All)]属性。这会修复异常“无法创建类型为“your interface”的实例。该类型是一个接口或抽象类,无法被实例化。” - DalSoft

2
使用这个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时,会添加带有“base”和“derived”值的“$type”,并且它将用于反序列化。
序列化列表示例:
[
    {"Name":"some name", "$type":"base"},
    {"Name":"some name", "Something":"something", "$type":"derived"}
]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接