web-dev-qa-db-ja.com

ポリモーフィックオブジェクトの配列を使用したJSONデシリアライズ

ポリモーフィックオブジェクトの配列を含むJSON逆シリアル化に問題があります。文書化されているシリアル化のソリューションを試しました ここ および ここ シリアル化には最適ですが、どちらも逆シリアル化で爆発します。

私のクラス構造は次のとおりです。

ID可能

[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またはNewtonsoftJSONライブラリのいずれかを使用することに公平です。

シリアル化コード

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のインスタンスを作成できませんでした。タイプはインターフェイスまたは抽象クラスであり、インスタンス化できません。」

どんな助けでも大歓迎です!

26
Chainlink

デシリアライズ時に設定を追加していません。 TypeNameHandlingObjectまたはAllに設定して設定を適用する必要があります。

このような:

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

ドキュメント: TypeNameHandling設定

28
asgerhallas