writer.WriteString (qn.Namespace);
} else if (TypeMap.IsDictionary (type)) {
writer.WriteAttributeString ("type", "array");
- var itemGetter = type.GetProperty ("Item");
- var keysGetter = type.GetProperty ("Keys");
- var argarr = new object [1];
- foreach (object o in (IEnumerable) keysGetter.GetValue (graph, null)) {
- writer.WriteStartElement ("item");
- writer.WriteAttributeString ("type", "object");
- // outputting a KeyValuePair as <Key .. /><Value ... />
- writer.WriteStartElement ("Key");
- WriteObjectContent (o, false, !(graph is Array && type.GetElementType () != typeof (object)));
- writer.WriteEndElement ();
- writer.WriteStartElement ("Value");
- argarr [0] = o;
- WriteObjectContent (itemGetter.GetValue (graph, argarr), false, !(graph is Array && type.GetElementType () != typeof (object)));
- writer.WriteEndElement ();
- writer.WriteEndElement ();
+ bool otn = !(graph is Array && type.GetElementType () != typeof (object));
+ var d = graph as IDictionary;
+ if (d != null) {
+ // Optimize the IDictionary case to avoid reflection
+ foreach (object k in d.Keys)
+ WriteItem (k, d [k], otn);
+ } else {
+ // we can't typecast to IDictionary<,> and can't use dynamic for iOS support
+ var itemGetter = GetDictionaryProperty (type, "Item");
+ var keysGetter = GetDictionaryProperty (type, "Keys");
+ var argarr = new object [1];
+ foreach (object o in (IEnumerable) keysGetter.GetValue (graph, null)) {
+ argarr [0] = o;
+ WriteItem (o, itemGetter.GetValue (graph, argarr), otn);
+ }
}
} else if (graph is Array || TypeMap.IsEnumerable (type)) {
writer.WriteAttributeString ("type", "array");
}
}
+ void WriteItem (object key, object value, bool outputTypeName)
+ {
+ writer.WriteStartElement ("item");
+ writer.WriteAttributeString ("type", "object");
+ // outputting a KeyValuePair as <Key .. /><Value ... />
+ writer.WriteStartElement ("Key");
+ WriteObjectContent (key, false, outputTypeName);
+ writer.WriteEndElement ();
+ writer.WriteStartElement ("Value");
+ WriteObjectContent (value, false, outputTypeName);
+ writer.WriteEndElement ();
+ writer.WriteEndElement ();
+ }
+
+ PropertyInfo GetDictionaryProperty (Type type, string propertyName)
+ {
+ var p = type.GetProperty (propertyName);
+ if (p != null)
+ return p;
+ // check explicit - but the generic names might differ, e.g. TKey,TValue vs T,V
+ var ap = type.GetProperties (BindingFlags.Instance | BindingFlags.NonPublic);
+ foreach (var cp in ap) {
+ if (!cp.Name.EndsWith (propertyName, StringComparison.Ordinal))
+ continue;
+ if (cp.Name.StartsWith ("System.Collections.Generic.IDictionary<", StringComparison.Ordinal))
+ return cp;
+ }
+ return null;
+ }
+
string FormatTypeName (Type type)
{
return String.Format ("{0}:#{1}", type.Name, type.Namespace);
Assert.AreEqual (1, dict.Count, "#2");
Assert.AreEqual ("value", dict ["key"], "#3");
}
-
+
+ [Test]
+ public void ExplicitCustomDictionarySerialization ()
+ {
+ var dict = new MyExplicitDictionary<string,string> ();
+ dict.Add ("key", "value");
+ var serializer = new DataContractJsonSerializer (dict.GetType ());
+ var stream = new MemoryStream ();
+ serializer.WriteObject (stream, dict);
+ stream.Position = 0;
+
+ Assert.AreEqual ("[{\"Key\":\"key\",\"Value\":\"value\"}]", new StreamReader (stream).ReadToEnd (), "#1");
+ stream.Position = 0;
+ dict = (MyExplicitDictionary<string,string>) serializer.ReadObject (stream);
+ Assert.AreEqual (1, dict.Count, "#2");
+ Assert.AreEqual ("value", dict ["key"], "#3");
+ }
+
[Test]
public void Bug13485 ()
{
}
}
+public class MyExplicitDictionary<K, V> : IDictionary<K, V> {
+
+ Dictionary<K,V> dic = new Dictionary<K,V> ();
+
+ public void Add (K key, V value)
+ {
+ dic.Add (key, value);
+ }
+
+ public bool ContainsKey (K key)
+ {
+ return dic.ContainsKey (key);
+ }
+
+ ICollection<K> IDictionary<K, V>.Keys {
+ get { return dic.Keys; }
+ }
+
+ public bool Remove (K key)
+ {
+ return dic.Remove (key);
+ }
+
+ public bool TryGetValue (K key, out V value)
+ {
+ return dic.TryGetValue (key, out value);
+ }
+
+ ICollection<V> IDictionary<K, V>.Values {
+ get { return dic.Values; }
+ }
+
+ public V this [K key] {
+ get { return dic [key]; }
+ set { dic [key] = value; }
+ }
+
+ IEnumerator IEnumerable.GetEnumerator ()
+ {
+ return dic.GetEnumerator ();
+ }
+
+ ICollection<KeyValuePair<K,V>> Coll {
+ get { return (ICollection<KeyValuePair<K,V>>) dic; }
+ }
+
+ public void Add (KeyValuePair<K, V> item)
+ {
+ Coll.Add (item);
+ }
+
+ public void Clear ()
+ {
+ dic.Clear ();
+ }
+
+ public bool Contains (KeyValuePair<K, V> item)
+ {
+ return Coll.Contains (item);
+ }
+
+ public void CopyTo (KeyValuePair<K, V> [] array, int arrayIndex)
+ {
+ Coll.CopyTo (array, arrayIndex);
+ }
+
+ public int Count {
+ get { return dic.Count; }
+ }
+
+ public bool IsReadOnly {
+ get { return Coll.IsReadOnly; }
+ }
+
+ public bool Remove (KeyValuePair<K, V> item)
+ {
+ return Coll.Remove (item);
+ }
+
+ public IEnumerator<KeyValuePair<K, V>> GetEnumerator ()
+ {
+ return Coll.GetEnumerator ();
+ }
+}
+
[DataContract]
public class Bug13485Type
{