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

时间:2011-08-17 14:59:41

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

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

我的班级结构如下:

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>();
    }

}

DescriptiveObservation

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

NumericObservation

[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类型的实例.Type是接口或抽象类,无法立即显示。”

非常感谢任何帮助!

2 个答案:

答案 0 :(得分:28)

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

像这样:

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

文档:TypeNameHandling setting

答案 1 :(得分:2)

使用此JsonKnownTypes,类似的方法:

[JsonConverter(typeof(JsonKnownTypeConverter<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"}
]