2016-06-19 11 views
0

List<string>をデシリアライズしようとしています。実際には、オブジェクトがシリアル化されたList<myClass>です。例:JSONのシリアル化されたオブジェクトのJSONリストを逆シリアル化する

static void Main(string[] args) 
{ 
    List<MyThirdClass> myThirdClass = new List<MyThirdClass>(new[] { new MyThirdClass { RoleId = 123, RoleName = "123" }, new MyThirdClass { RoleId = 234, RoleName = "234" } }); 
    List<MySecondSerializedClass> mySecondSerializedClass = new List<MySecondSerializedClass>(); 
    foreach (MyThirdClass thirdClass in myThirdClass) 
    { 
     MySecondSerializedClass secondClass = new MySecondSerializedClass { Roles = new List<string>() }; 
     foreach (MyThirdClass tClass in myThirdClass) 
     { 
      secondClass.Roles.Add(JsonConvert.SerializeObject(tClass)); 
     } 
     mySecondSerializedClass.Add(secondClass); 
    } 
    MyFirstSerializedClass firstClass = new MyFirstSerializedClass 
    { 
     Id = 1, 
     Name = "1", 
     Roles = mySecondSerializedClass 
    }; 

    string serializedFirstClass = JsonConvert.SerializeObject(firstClass, Formatting.Indented); 
    MyFirstNonSerializedClass nonSerializedFirstClass = JsonConvert.DeserializeObject<MyFirstNonSerializedClass>(serializedFirstClass); 
} 

public class MyFirstSerializedClass 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public List<MySecondSerializedClass> Roles { get; set; } 
} 

public class MyFirstNonSerializedClass 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public List<MySecondNonSerializedClass> Roles { get; set; } 
} 

public class MySecondSerializedClass 
{ 
    public List<string> Roles { get; set; } 
} 

public class MySecondNonSerializedClass 
{ 
    public List<MyThirdClass> Roles { get; set; } 
} 

public class MyThirdClass 
{ 
    public int RoleId { get; set; } 
    public string RoleName { get; set; } 
} 

serializedFirstClassこのようなJSONを返す:

{ 
    "Id": 1, 
    "Name": "1", 
    "Roles": [ 
    { 
     "Roles": [ 
     "{\"RoleId\":123,\"RoleName\":\"123\"}", 
     "{\"RoleId\":234,\"RoleName\":\"234\"}" 
     ] 
    }, 
    { 
     "Roles": [ 
     "{\"RoleId\":123,\"RoleName\":\"123\"}", 
     "{\"RoleId\":234,\"RoleName\":\"234\"}" 
     ] 
    } 
    ] 
} 

デシリアライズは、メッセージと例外をスローしようとしている:値を変換

エラー "{" RoleId ":123、" RoleName ":" 123 "}"を入力して 'ConsoleApplication1.Program + MyThirdClass'と入力します。パスの役割[0] .Roles [0] '、7行目、位置47

は私が間違っているの何かまたは再帰的MyFirstNonSerializedClassにMyFirstSerializedClassをデシリアライズする方法はありますか?

+0

なぜ内部ロールの間に外部ロールがエスケープされないのですか? – abatishchev

+0

@abatishchev私は文字列としてロールをシリアライズしてからそれらを再直列化するためだと思います –

+0

リストとしてMySecondNonSerializedClassのロールを宣言します abatishchev

答えて

1

あなたは、その後のインスタンスとしてJSONからリテラルその文字列をデシリアライズするために、ネストされたシリアライザを使用して、文字列リテラルとして、現在のJSONトークンを読み込み、クラスの単一のセットとMyThirdClassのためのオプションのJsonConverterでこれを行うことができますMyThirdClass。埋め込み文字列としてクラスをシリアル化または逆シリアル化する場合は、コンバータをJsonSerializerSettings.Convertersに追加します。それをオブジェクトとして直列化することはできません。したがって

:コンバータは直接もたらす[JsonConverter(typeof(MyThirdClassStringConverter))]として無限の再帰を使用してMyThirdClassに適用されるべきではないこと

var stringSettings = new JsonSerializerSettings { Converters = new[] { new MyThirdClassStringConverter() } }; 

// Deserialize JSON where MyThirdClass objects are embedded strings 
var root = JsonConvert.DeserializeObject<MyFirstClass>(stringJson, stringSettings); 

// Re-serialize to JSON where MyThirdClass objects are objects 
var newNonStringJson = JsonConvert.SerializeObject(root, Formatting.Indented); 
// Re-serialize to JSON where MyThirdClass objects are embedded strings 
var newStringJson = JsonConvert.SerializeObject(root, Formatting.Indented, stringSettings); 

注:次のように

public class MyFirstClass 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public List<MySecondClass> Roles { get; set; } 
} 

public class MySecondClass 
{ 
    public List<MyThirdClass> Roles { get; set; } 
} 

public class MyThirdClass 
{ 
    public int RoleId { get; set; } 
    public string RoleName { get; set; } 
} 

public sealed class MyThirdClassStringConverter : JsonConverter 
{ 
    readonly JsonSerializerSettings settings; 

    public MyThirdClassStringConverter() : this(null) { } 

    public MyThirdClassStringConverter(JsonSerializerSettings settings) 
    { 
     this.settings = settings; 
    } 

    JsonSerializer GetInnerSerializer() 
    { 
     var innerSerializer = JsonSerializer.CreateDefault(settings); 
     for (int i = innerSerializer.Converters.Count - 1; i >= 0; i--) 
      if (innerSerializer.Converters[i] is MyThirdClassStringConverter) 
       innerSerializer.Converters.RemoveAt(i); 
     return innerSerializer; 
    } 

    public override bool CanConvert(Type objectType) 
    { 
     return typeof(MyThirdClass).IsAssignableFrom(objectType); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     if (reader.TokenType == JsonToken.Null) 
      return null; 
     var innerSerializer = GetInnerSerializer(); 
     if (reader.TokenType == JsonToken.String) 
     { 
      var s = reader.Value.ToString(); 
      using (var innerReader = new StringReader(s)) 
       return innerSerializer.Deserialize(innerReader, objectType); 
     } 
     else 
     { 
      return innerSerializer.Deserialize(reader, objectType); 
     } 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     var innerSerializer = GetInnerSerializer(); 
     var sb = new StringBuilder(); 
     using (var innerWriter = new StringWriter(sb)) 
      innerSerializer.Serialize(innerWriter, value); 
     writer.WriteValue(sb.ToString()); 
    } 
} 

そして、それを使用します。コンバータのReadJson()メソッドは、現在のトークンが文字列かオブジェクトかを調べ、それに応じて適合するかどうかを調べるため、どちらの形式でもJSONを逆シリアル化するために使用できます。

fiddle

+0

答えが最も完全であるため、回答を受け入れていますが、オブジェクトを二重にシリアライズしないクラスで別のパスを行った –

1

stringMyThirdClassの構造をデシリアライズすることはできません。

実際には同じではありません。 ":\ "SomePropertyValue \" SomeProperty2 \ "\" SomePropertyValue \」"
: "\" 文字列の

一覧はSomeProperty \ "\"

にシリアライズされます"

CustomClassの一覧は

なりますが

"SomeProperty": "SomePropertyValue"、
"SomeProperty2": "SomeProperty2Value"

+0

どうすればそれを後でデシリアライズすることができますか?この二重シリアル化は、ATS(Azure Table Storage)テーブルに格納するためのものです。いくつかのサンプルコードは素晴らしいでしょう –

1

は、あなたが文字列に変換しMyThirdClassをシリアル化します。 デシリアライズ時に逆変換が必要です。文字列から型への暗黙の変換を追加します。

public static implicit operator MyThirdClass(string s) 
{ 
    // when serializing indented => 
    // return JsonConvert.DeserializeObject<B3>(s, new JsonSerializerSettings() { Formatting = Formatting.Indented}); 
    // otherwise 
    return JsonConvert.DeserializeObject<B3>(s); 
} 
+0

ありがとう、私はシリアライズされたクラスを削除し、別のアプローチに従った。 –

関連する問題