2017-01-19 5 views
0

インタフェースのコレクションデシリアライズ:完全に直列化可能である、私は以下のクラスを持っている

public class Form { 
    public IList<IControl> Controls { get; set; } 
} 

public class ControlA : IControl {} 
public class ControlB : IControl {} 

それは$type情報なしシリアライズが、私はIControlすべて実装をデシリアライズすることができますカスタムJsonConverterを持っていました:

internal class MyJsonConverter : CustomCreationConverter<IControl> {} 

[JsonConverter(typeof(MyJsonConverter))] 
public IControl MyControl {get;set;} 

しかし、私は私のForm.Controlsプロパティに同じJsonConverterAttributeを適用することはできません。JsonReaderからjオブジェクトを読ん

「エラー。現在のJsonReaderアイテムは オブジェクトではありません:StartArray。パス「コントロール」、5行目、位置15.」

どのように私はデシリアライザがForm.Controlsコレクション内の項目ためMyJsonConverterを使用するように指示していますか?

答えて

1

あなたは、コレクション内の項目には、コンバータを適用するために[JsonProperty(ItemConverterType = typeof(MyJsonConverter))]を使用することができます。

public class Form 
{ 
    [JsonProperty(ItemConverterType = typeof(MyJsonConverter))] 
    public IList<IControl> Controls { get; set; } 
} 
+0

それはまさにそれです!ありがとうございました。 – UserControl

1

私はあなたのMyJsonConverterが実際にしかしとして何をするかわかりません基本的な例は、あなただけのJsonSerializerSettingsを提供する必要があり、この単純な例では、作品TypeNameHandling.All

TypeNameHandlingプロパティを設定する必要があります。

public interface IControl { } 

public class Form 
{ 
    public IList<IControl> Controls { get; set; } 
} 

public class ControlA : IControl { } 
public class ControlB : IControl { } 

static void Main(string[] args) 
{ 
    var form = new Form(); 
    form.Controls = new List<IControl>(); 

    form.Controls.Add(new ControlA()); 
    form.Controls.Add(new ControlB()); 
    var json = JsonConvert.SerializeObject(form, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All }); 
    var obj = JsonConvert.DeserializeObject<Form>(json, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All }); 
} 

編集

なしタイプの取り扱いは、したがって、我々はもう少し創造的な取得と生jSONを読む必要が全く$typeプロパティを使用していないされていないことを明確化した後。そして、特別な方法でオブジェクトを構築します。次に、シリアライザの例を示します。

internal class MyJsonConverter : CustomCreationConverter<IControl> 
{ 
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     var jObject = JObject.Load(reader); 
     var controlType = jObject["CustomProperty"]?.Value<string>(); 

     IControl control = null; 

     if (!string.IsNullOrWhiteSpace(controlType)) 
     { 
      switch (controlType.ToLowerInvariant()) 
      { 
       case "controla": 
        control = Activator.CreateInstance(typeof(ControlA)) as IControl; 
        break; 
       case "controlb": 
        control = Activator.CreateInstance(typeof(ControlB)) as IControl; 
        break; 
      } 
     } 
     if (controlType == null) 
      throw new SerializationException($"Unable to deserialize property. {controlType}"); 

     serializer.Populate(jObject.CreateReader(), control); 
     return control; 
    } 

    public override IControl Create(Type objectType) 
    { 
     return null; 
    } 
} 

基本的に我々は(問題のommitedされています)IControlインタフェースのプロパティにdepndingされているとして、我々は、手動でJSONを解析し、このプロパティはexsits場合はプロパティにCustomProperty

を参照を取得します有効な文字列値で(または他の値を使用することもできます)、IControlを手動で作成します。

最後のデシリアライズを扱う作品は最終ラインserializer.Populate()

完全なテストケースである:

internal class MyJsonConverter : CustomCreationConverter<IControl> 
{ 
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     var jObject = JObject.Load(reader); 
     var controlType = jObject["CustomProperty"]?.Value<string>(); 

     IControl control = null; 

     if (!string.IsNullOrWhiteSpace(controlType)) 
     { 
      switch (controlType.ToLowerInvariant()) 
      { 
       case "controla": 
        control = Activator.CreateInstance(typeof(ControlA)) as IControl; 
        break; 
       case "controlb": 
        control = Activator.CreateInstance(typeof(ControlB)) as IControl; 
        break; 
      } 
     } 
     if (controlType == null) 
      throw new SerializationException($"Unable to deserialize property. {controlType}"); 

     serializer.Populate(jObject.CreateReader(), control); 
     return control; 
    } 

    public override IControl Create(Type objectType) 
    { 
     return null; 
    } 
} 


[JsonConverter(typeof(MyJsonConverter))] 
public interface IControl 
{ 
    string CustomProperty { get; set; } 
} 

public class Form 
{ 
    public IList<IControl> Controls { get; set; } 
} 

public class ControlA : IControl 
{ 
    public string CustomProperty { get; set; } = "ControlA"; 
} 
public class ControlB : IControl 
{ 
    public string CustomProperty { get; set; } = "ControlB"; 
} 

static void Main(string[] args) 
{ 
    var form = new Form(); 
    form.Controls = new List<IControl>(); 
    form.Controls.Add(new ControlA()); 
    form.Controls.Add(new ControlB()); 
    var json = JsonConvert.SerializeObject(form); 
    var obj = JsonConvert.DeserializeObject<Form>(json); 
} 
+0

私のjsonにデフォルトの型情報( '$ type' prop)がありません。 – UserControl

+0

オブジェクトがどのタイプであるかを知るには、それを必要とするでしょうか? – Nico

+0

'MyJsonConverter'はカスタムプロパティを調べてそれを知っています – UserControl

関連する問題