2011-06-20 19 views
7

IDictionary<string,object>は、KeyValuePairオブジェクトの配列(例:[{Key:"foo", Value:"bar"}, ...])としてシリアル化されているようです。代わりにオブジェクトとしてシリアル化することはできますか(たとえば、{foo:"bar"})?JavaScriptSerializerを使用して辞書をシリアライズ

+3

はい、JavaScriptSerializer、その全くがらくたを使用してはいけません。使用Newtonsoft Json.NET –

答えて

10

私はJavaScriptSerializerはがらくたであるとJson.Netがより良い選択肢であることに同意しますが、 JavaScriptSerializerを必要な方法で直列化できるようにする方法があります。 あなたは、コンバータを登録し、このようなものを使用してSerializeメソッドをオーバーライドする必要があります。

public class KeyValuePairJsonConverter : JavaScriptConverter 
{ 
    public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer) 
    { 
     var instance = Activator.CreateInstance(type); 

     foreach (var p in instance.GetType().GetPublicProperties()) 
     { 
      instance.GetType().GetProperty(p.Name).SetValue(instance, dictionary[p.Name], null); 
      dictionary.Remove(p.Name); 
     } 

     foreach (var item in dictionary) 
      (instance).Add(item.Key, item.Value); 

     return instance; 
    } 
    public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer) 
    { 
     var result = new Dictionary<string, object>(); 
     var dictionary = obj as IDictionary<string, object>; 
     foreach (var item in dictionary) 
      result.Add(item.Key, item.Value); 
     return result; 
    } 
    public override IEnumerable<Type> SupportedTypes 
    { 
     get 
     { 
      return new ReadOnlyCollection<Type>(new Type[] { typeof(your_type) }); 
     } 
    } 
} 

JavaScriptSerializer javaScriptSerializer = new JavaScriptSerializer(); 
javaScriptSerializer.RegisterConverters(new JavaScriptConverter[] { new ExpandoJsonConverter() }); 
jsonOfTest = javaScriptSerializer.Serialize(test); 
// {"x":"xvalue","y":"\/Date(1314108923000)\/"} 

ホープ、このことができます!

+0

あなたのクラスを使用しようとしていますが、 'Class Object'の' instance'変数にはaddメソッドがありません。 –

4

いいえ、JavaScriptSerializerではできません。それはJson.NETで可能です:その後、

public class Bar 
{ 
    public Bar() 
    { 
     Foos = new Dictionary<string, string> 
     { 
      { "foo", "bar" } 
     }; 
    } 

    public Dictionary<string, string> Foos { get; set; } 
} 

と:

var bar = new Bar(); 
string json = JsonConvert.SerializeObject(bar, new KeyValuePairConverter()); 

は希望を生み出す:

{"Foos":{"foo":"bar"}} 
+0

私は最初にそのルートに行っていた。以前の質問:http://stackoverflow.com/questions/6416017/json-net-deserializing-nested-dictionariesを参照してください。 Json.NETでネストされた辞書をデシリアライズする際に問題が発生しました。 – Daniel

+2

@Daniel、Json.NETは 'JavaScriptSerializer'と比較して砂糖です。だからあなたがJson.NETに問題がある場合、私は代替案について何を言いたいのか分からない:-)あなたの他の質問に関しては、それは完全に正常な動作です。シリアライザに指示したのは、文字列とオブジェクトの辞書です。だからあなたは弱い型の辞書で作業しているのですが、何の代わりに期待していますか?あなたが得ることができるのは、弱く型付けされたJObjectsだけです。厳密に型付けされた辞書を使用してください: 'Dictionary '、違いがあります。 –

+0

どのような違いがありますか?私はそれを見ていないよ。 – Daniel

1

私はJavaScriptSerializerを使用してそれを解決することができました。トリックは独自のコンバータを作成することです。次のコードは、コードを働いている:

public class KeyValuePairJsonConverter : JavaScriptConverter { 
    public override object Deserialize(IDictionary<string, object> dictionary 
             , Type type 
             , JavaScriptSerializer serializer) { 
     throw new InvalidOperationException("Sorry, I do serializations only."); 
    } 

    public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer) { 
     Dictionary<string, object> result = new Dictionary<string, object>(); 
     Dictionary<string, MyClass> dictionaryInput = obj as Dictionary<string, MyClass>; 

     if (dictionaryInput == null) { 
      throw new InvalidOperationException("Object must be of Dictionary<string, MyClass> type."); 
     } 

     foreach (KeyValuePair<string, MyClass> pair in dictionaryInput) 
      result.Add(pair.Key, pair.Value); 

     return result; 
    } 

    public override IEnumerable<Type> SupportedTypes { 
     get { 
      return new ReadOnlyCollection<Type>(new Type[] { typeof(Dictionary<string, MyClass>) }); 
     } 
    } 
} 

そして、ここでは、あなたがそれを使用する方法は次のとおりです。

JavaScriptSerializer js = new JavaScriptSerializer(); 
js.RegisterConverters(new JavaScriptConverter[] { new KeyValuePairJsonConverter() }); 
Context.Response.Clear(); 
Context.Response.ContentType = "application/json"; 
Context.Response.Write(js.Serialize(myObject)); 
1

ここで私はトーマスの答えからの改良版を信じています。魅力のように動作します。 ScriptIgnore属性のチェックを追加することもできますが、うまくいきません。

私の意見では、サードパーティーのソリューションはほとんど知られていないため、インストールに時間がかかり、しばしば忘れてしまった前提条件を忘れていて、事業に配備するのが危険なコピーライト状態になっていたからです。

P-S:私がなぜインスタンスとインスタンスの両方を辞書としてデシリアライズしようとしているのか分からなかったので、その部分を取り除いた。

public class KeyValuePairJsonConverter : JavaScriptConverter 
{ 
    public override object Deserialize(IDictionary<string, object> deserializedJSObjectDictionary, Type targetType, JavaScriptSerializer javaScriptSerializer) 
    { 
     Object targetTypeInstance = Activator.CreateInstance(targetType); 

     FieldInfo[] targetTypeFields = targetType.GetFields(BindingFlags.Public | BindingFlags.Instance); 

     foreach (FieldInfo fieldInfo in targetTypeFields) 
      fieldInfo.SetValue(targetTypeInstance, deserializedJSObjectDictionary[fieldInfo.Name]); 

     return targetTypeInstance; 
    } 

    public override IDictionary<string, object> Serialize(Object objectToSerialize, JavaScriptSerializer javaScriptSerializer) 
    { 
     IDictionary<string, object> serializedObjectDictionary = new Dictionary<string, object>(); 

     FieldInfo[] objectToSerializeTypeFields = objectToSerialize.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance); 

     foreach (FieldInfo fieldInfo in objectToSerializeTypeFields) 
      serializedObjectDictionary.Add(fieldInfo.Name, fieldInfo.GetValue(objectToSerialize)); 

     return serializedObjectDictionary; 
    } 

    public override IEnumerable<Type> SupportedTypes 
    { 
     get 
     { 
      return new ReadOnlyCollection<Type>(new Type[] { typeof(YOURCLASSNAME) }); 
     } 
    } 
} 
+0

私のPSノートについて。おそらくこれは型ではなく汎用の辞書型を指定できるようにすることでしたが、正直なところ、汎用辞書型を指定する点はありません。の辞書を逆シリアル化することです。そしてそれはキューボです。 – Olograph

2

私はLINQを選択してJavaScriptSerializerで解決することができた:

var dictionary = new Dictionary<int, string>(); 
var jsonOutput = new JavaScriptSerializer().Serialize(dictionary.Select(x => new { Id = x.Key, DisplayText = x.Value })); 
+0

これは複雑なケース(複雑な階層構造)では機能しませんが、単純なケースでは問題が解決されるため、JavaScriptSerializerやサードパーティのライブラリに定型句を追加しないようにしたい場合には、 –

+0

私にとっては複雑な場合でも '.Serialize(辞書)'に変更してもうまくいきました。そのシンプルなJsonConvertはすぐに使えます。私はこの答えに+2を与えることができたらいいと思う –

関連する問題