OSDN Git Service

JSONオブジェクトのメンバー順を保存する
authorKazuhiro Fujieda <fujieda@users.osdn.me>
Sat, 24 Mar 2018 10:41:25 +0000 (19:41 +0900)
committerKazuhiro Fujieda <fujieda@users.osdn.me>
Sat, 24 Mar 2018 10:41:25 +0000 (19:41 +0900)
KancolleSniffer.Test/JsonTest.cs
KancolleSniffer/JsonParser.cs

index 5ca5dd6..58f6a4d 100644 (file)
@@ -231,6 +231,18 @@ namespace KancolleSniffer.Test
         }\r
 \r
         [TestMethod]\r
+        public void PropertyOrder()\r
+        {\r
+            const int count = 100;\r
+            var json = "{" + string.Join(",", Enumerable.Range(0, count).Select(n => $"\"{"a" + n}\":{n}")) + "}";\r
+            var obj = (dynamic)JsonParser.Parse(json);\r
+            var list = new List<int>();\r
+            foreach (KeyValuePair<string, dynamic> kv in obj)\r
+                list.Add((int)kv.Value);\r
+            Assert.IsTrue(list.SequenceEqual(Enumerable.Range(0, count)));\r
+        }\r
+\r
+        [TestMethod]\r
         public void CastArrayToPrimitivetArray()\r
         {\r
             var bary = (bool[])(dynamic)JsonParser.Parse("[true,false,true]");\r
index 0c4baf6..b3884de 100644 (file)
@@ -1,6 +1,7 @@
 using System;\r
 using System.Collections;\r
 using System.Collections.Generic;\r
+using System.Collections.Specialized;\r
 using System.Dynamic;\r
 using System.Linq;\r
 using System.Reflection;\r
@@ -187,7 +188,7 @@ namespace KancolleSniffer
         private JsonObject ParseObject()\r
         {\r
             Consume();\r
-            var dict = new Dictionary<string, JsonObject>();\r
+            var dict = new OrderedDictionary();\r
             while (true)\r
             {\r
                 var ch = NextChar();\r
@@ -250,11 +251,11 @@ namespace KancolleSniffer
         private readonly double _number;\r
         private readonly string _string;\r
         private readonly List<JsonObject> _array;\r
-        private readonly Dictionary<string, JsonObject> _dict;\r
+        private readonly OrderedDictionary _dict;\r
 \r
         public bool IsArray => _type == JsonType.Array;\r
         public bool IsObject => _type == JsonType.Object;\r
-        public bool IsDefined(string attr) => IsObject && _dict.ContainsKey(attr);\r
+        public bool IsDefined(string attr) => IsObject && _dict.Contains(attr);\r
 \r
         public JsonObject(bool b)\r
         {\r
@@ -280,7 +281,7 @@ namespace KancolleSniffer
             _array = ary;\r
         }\r
 \r
-        public JsonObject(Dictionary<string, JsonObject> dict)\r
+        public JsonObject(OrderedDictionary dict)\r
         {\r
             _type = JsonType.Object;\r
             _dict = dict;\r
@@ -291,15 +292,15 @@ namespace KancolleSniffer
             result = null;\r
             if (_type != JsonType.Object)\r
                 return false;\r
-            if (!_dict.TryGetValue(binder.Name, out var dict))\r
+            if (!_dict.Contains(binder.Name))\r
                 return false;\r
-            result = dict?.Value;\r
+            result = ((JsonObject)_dict[binder.Name])?.Value;\r
             return true;\r
         }\r
 \r
         public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)\r
         {\r
-            result = _type == JsonType.Object && _dict.ContainsKey(binder.Name);\r
+            result = _type == JsonType.Object && _dict.Contains(binder.Name);\r
             return true;\r
         }\r
 \r
@@ -311,7 +312,7 @@ namespace KancolleSniffer
                     result = _array[(int)indexes[0]]?.Value;\r
                     return true;\r
                 case JsonType.Object:\r
-                    result = _dict[(string)indexes[0]]?.Value;\r
+                    result = ((JsonObject)_dict[(string)indexes[0]])?.Value;\r
                     return true;\r
             }\r
             result = null;\r
@@ -328,7 +329,7 @@ namespace KancolleSniffer
                         result = _array.Select(x => x.Value);\r
                         return true;\r
                     case JsonType.Object:\r
-                        result = _dict.Select(x => new KeyValuePair<string, dynamic>(x.Key, x.Value));\r
+                        result = _dict.Cast<DictionaryEntry>().Select(x => new KeyValuePair<string, dynamic>((string)x.Key, x.Value));\r
                         return true;\r
                     default:\r
                         result = null;\r
@@ -419,8 +420,10 @@ namespace KancolleSniffer
                 case IEnumerable arry:\r
                     return new JsonObject(arry.Cast<object>().Select(CreateJsonObject).ToList());\r
                 case object obj:\r
-                    return new JsonObject(obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)\r
-                        .ToDictionary(prop => prop.Name, prop => CreateJsonObject(prop.GetValue(obj))));\r
+                    var dict = new OrderedDictionary();\r
+                    foreach (var prop in obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))\r
+                        dict.Add(prop.Name, CreateJsonObject(prop.GetValue(obj)));\r
+                    return new JsonObject(dict);\r
             }\r
             return null;\r
         }\r
@@ -491,7 +494,7 @@ namespace KancolleSniffer
                 case JsonType.Object:\r
                     sb.Append("{");\r
                     delimiter = "";\r
-                    foreach (var entry in _dict)\r
+                    foreach (DictionaryEntry entry in _dict)\r
                     {\r
                         sb.Append(delimiter);\r
                         sb.Append("\"");\r
@@ -503,7 +506,7 @@ namespace KancolleSniffer
                         }\r
                         else\r
                         {\r
-                            entry.Value.ConvertToString(sb);\r
+                            ((JsonObject)entry.Value).ConvertToString(sb);\r
                         }\r
                         delimiter = ",";\r
                     }\r