2011-07-26 14 views
6

JSON.netを使用してオブジェクトに逆シリアル化するが、マッピングされていないプロパティを辞書プロパティに配置したいと思う。出来ますか?例えばjsonをオブジェクトにキャストすべての辞書プロパティで

JSON、

{one:1,two:2,three:3} 

とC#のクラス所与:

public class Mapped { 
    public int One {get; set;} 
    public int Two {get; set;} 
    public Dictionary<string,object> TheRest {get; set;} 
} 

JSON.NETは、値1 = 1でインスタンス= 1〜2をデシリアライズでき、TheRest =辞書{{"three、3}}

+0

。 –

答えて

2

あなたがする必要があることを行うためにCustomCreationConverterを作成することができます。これはサンプルです(むしろ醜いですが、これについてはどうやって見てみましょうか):

namespace JsonConverterTest1 
{ 
    public class Mapped 
    { 
     private Dictionary<string, object> _theRest = new Dictionary<string, object>(); 
     public int One { get; set; } 
     public int Two { get; set; } 
     public Dictionary<string, object> TheRest { get { return _theRest; } } 
    } 

    public class MappedConverter : CustomCreationConverter<Mapped> 
    { 
     public override Mapped Create(Type objectType) 
     { 
      return new Mapped(); 
     } 

     public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
     { 
      var mappedObj = new Mapped(); 
      var objProps = objectType.GetProperties().Select(p => p.Name.ToLower()).ToArray(); 

      //return base.ReadJson(reader, objectType, existingValue, serializer); 
      while (reader.Read()) 
      { 
       if (reader.TokenType == JsonToken.PropertyName) 
       { 
        string readerValue = reader.Value.ToString().ToLower(); 
        if (reader.Read()) 
        { 
         if (objProps.Contains(readerValue)) 
         { 
          PropertyInfo pi = mappedObj.GetType().GetProperty(readerValue, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance); 
          var convertedValue = Convert.ChangeType(reader.Value, pi.PropertyType); 
          pi.SetValue(mappedObj, convertedValue, null); 
         } 
         else 
         { 
          mappedObj.TheRest.Add(readerValue, reader.Value); 
         } 
        } 
       } 
      } 
      return mappedObj; 
     } 
    } 

    public class Program 
    { 
     static void Main(string[] args) 
     { 
      string json = "{'one':1, 'two':2, 'three':3, 'four':4}"; 

      Mapped mappedObj = JsonConvert.DeserializeObject<Mapped>(json, new MappedConverter()); 

      Console.WriteLine(mappedObj.TheRest["three"].ToString()); 
      Console.WriteLine(mappedObj.TheRest["four"].ToString()); 
     } 
    } 
} 

ですから、JSON文字列をデシリアライズした後mappedObjの出力は、人口のOneTwoプロパティを持つオブジェクトになり、そして他のすべてはDictionaryに入れます。確かに、私は1と2の値をintとハードコーディングしましたが、これはあなたがこれについてどうやっていくのかを示していると思います。

こちらがお役に立てば幸いです。

EDIT:コードを更新してより一般的なものにしました。私はそれを完全にテストしていないので、失敗するケースがいくつかあるかもしれませんが、そこではほとんどの方法が得られます。

+0

デビッドは素晴らしいですが、私はもっと汎用的なソリューションを望んでいました。 – PhilHoy

+0

ええ、私はそれを素早く一種にまとめました。私はすぐにそれに戻ることはできませんが、私はまもなくもう少し一般的にするつもりです。それはおそらく少しの反省を伴います。しかし、基本構造は変更されません。第2のif(reader.Read())ブロックのロジックだけです。しかし、うまくいけば、私はこれでどこに行くのか分かります。ところで、あなたが尋ねた非常にクールな質問。 –

+0

コードを更新して、異なるプロパティ名やタイプの汎用性を高めました。 –

1

これを行う最も簡単な方法は、JsonExtensionData属性を使用してすべての辞書を定義することです。 the Json.Net documentationから

例:それはより一般的にするために私の答えでコードを更新しました

public class DirectoryAccount 
{ 
    // normal deserialization 
    public string DisplayName { get; set; } 

    // these properties are set in OnDeserialized 
    public string UserName { get; set; } 
    public string Domain { get; set; } 

    [JsonExtensionData] 
    private IDictionary<string, JToken> _additionalData; 

    [OnDeserialized] 
    private void OnDeserialized(StreamingContext context) 
    { 
     // SAMAccountName is not deserialized to any property 
     // and so it is added to the extension data dictionary 
     string samAccountName = (string)_additionalData["SAMAccountName"]; 

     Domain = samAccountName.Split('\\')[0]; 
     UserName = samAccountName.Split('\\')[1]; 
    } 

    public DirectoryAccount() 
    { 
     _additionalData = new Dictionary<string, JToken>(); 
    } 
} 

string json = @"{ 
    'DisplayName': 'John Smith', 
    'SAMAccountName': 'contoso\\johns' 
}"; 

DirectoryAccount account = JsonConvert.DeserializeObject<DirectoryAccount>(json); 

Console.WriteLine(account.DisplayName); 
// John Smith 

Console.WriteLine(account.Domain); 
// contoso 

Console.WriteLine(account.UserName); 
// johns 
関連する問題