2013-10-22 6 views
5

私は実際のコードの簡単な例を持っています。 JSONにシリアライズし、Lettersから派生したクラスTestClassの逆オブジェクトを逆直列化する必要があります。どちらのクラスもパラメータ付きのコンストラクタを持っています。 TestClassコレクションは固定サイズのため、デシリアライズできません。

public class TestClass : Letters 
    { 
     public string[] Names { get; private set; } 

     public TestClass(string[] names) 
      : base(names) 
      // : base(new [] { "A", "B", }) 
      // : base(names.Select(a => a.Substring(0, 1)).ToArray()) 
     { 
      Names = names; 
     } 
    } 

    public abstract class Letters 
    { 
     public string[] FirstLetters { get; private set; } 

     protected Letters(string[] letters) 
     { 
      FirstLetters = letters; 
     } 
    } 

オブジェクトが有効なJSONにシリアライズされているが、私はそれが戻ってオブジェクトにデシリアライズしようとすると、非サポート例外は、メッセージコレクションにスローで固定サイズでした。

は、ここでそれ以外の場合は、コンストラクタを呼び出す方法を知らない、私のテストにそれらをデシリアライズするために、パラメータなしのコンストラクタを持っているすべてのクラスを必要とJson.Net

[Fact] 
    public void JsonNamesTest() 
    { 
     var expected = new TestClass(new [] { "Alex", "Peter", "John", }); 

     var serialized = JsonConvert.SerializeObject(expected); 
     Console.WriteLine(serialized); 

     Assert.False(string.IsNullOrWhiteSpace(serialized)); 

     var actual = JsonConvert.DeserializeObject<TestClass>(serialized); 

     AssertEx.PrimitivePropertiesEqual(expected, actual); 
    } 
+0

を持っている唯一のパブリックコンストラクタですリスト 'の? –

+0

私はクラスを直列化して逆直列化する必要があるので、存在し、変更するのは簡単ではありません。最後にすべてのクラスを書き直すことができます。 – Rudis

答えて

6

です。クラスを変更せずにこれを回避する方法の1つは、JSONからオブジェクトインスタンスを作成するカスタムJsonConverterを作成することです。その後

class TestClassConverter : JsonConverter 
{ 
    public override bool CanConvert(Type objectType) 
    { 
     return typeof(TestClass) == objectType; 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     JObject jo = JObject.Load(reader); 
     string[] names = jo["Names"].ToObject<string[]>(); 
     return new TestClass(names); 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     serializer.Serialize(writer, value); 
    } 
} 

、このようなあなたのクラスをデシリアライズし、それが動作するはずです:例えば

var actual = JsonConvert.DeserializeObject<TestClass>(serialized, new TestClassConverter()); 
1

感謝、それは働きます!私は私の例でより一般的な用法のためにあなたのコードを修正しました。

は、私が思う

  • シリアル化されたパラメータは、コンストラクタのパラメータと同じ名前(無視する場合)あなたの代わりに配列を使用しなければならないのはなぜ

    public class ParametersContructorConverter : JsonConverter 
    { 
        public override bool CanConvert(Type objectType) 
        { 
         return typeof(Letters).IsAssignableFrom(objectType); 
        } 
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
        { 
         var jo = JObject.Load(reader); 
         var contructor = objectType.GetConstructors().FirstOrDefault(); 
    
         if (contructor == null) 
         { 
          return serializer.Deserialize(reader); 
         } 
    
         var parameters = contructor.GetParameters(); 
         var values = parameters.Select(p => jo.GetValue(p.Name, StringComparison.InvariantCultureIgnoreCase).ToObject(p.ParameterType)).ToArray(); 
    
         return contructor.Invoke(values); 
        } 
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
        { 
         serializer.Serialize(writer, value); 
        } 
    } 
    
関連する問題