From 06ba17a22c025fb9ff6ed558ede7075205921278 Mon Sep 17 00:00:00 2001 From: KaiLin Ge Date: Thu, 1 Feb 2018 00:55:40 +0800 Subject: [PATCH 1/4] better custom type, fix List & Dictionary deserialization --- UnitTests/Tests.cs | 78 +++++++++++++++++++++++++++++++------- fastJSON/JSON.cs | 38 +++++++++++++------ fastJSON/JsonSerializer.cs | 7 +++- fastJSON/Reflection.cs | 4 +- 4 files changed, 100 insertions(+), 27 deletions(-) diff --git a/UnitTests/Tests.cs b/UnitTests/Tests.cs index 1905dbe..8c40542 100644 --- a/UnitTests/Tests.cs +++ b/UnitTests/Tests.cs @@ -291,7 +291,7 @@ public class RetNestedclass #endregion - [TestFixtureSetUp] + [OneTimeSetUp] public static void setup() { //fastJSON.JSON.Parameters = new JSONParameters(); @@ -1864,24 +1864,76 @@ public static void comments() Assert.AreEqual(2, (o as IDictionary).Count); } - public class ctype + public struct Point { - public System.Net.IPAddress ip; + public int x; + public float y; + } + public class Complex + { + public int i; + public List l; } [Test] public static void CustomTypes() { - var ip = new ctype(); - ip.ip = System.Net.IPAddress.Loopback; - - JSON.RegisterCustomType(typeof(System.Net.IPAddress), - (x) => { return x.ToString(); }, - (x) => { return System.Net.IPAddress.Parse(x); }); - - var s = JSON.ToJSON(ip); + JSON.RegisterCustomType(typeof(Point), + (o) => { + var pt = (Point)o; + return string.Format("[{0},{1}]", pt.x, pt.y); + }, + (o, cb) => { + var l = o as List; + return new Point() { x = Convert.ToInt32(l[0]), y = Convert.ToSingle(l[1]) }; + }); + JSON.RegisterCustomType(typeof(Complex), + (o) => { + var c = (Complex)o; + return string.Format("[{0},{1}]", c.i, JSON.ToJSON(c.l)); + }, + (o, cb) => { + var l = o as List; + return new Complex() { i = Convert.ToInt32(l[0]), l = (List)cb(l[1], typeof(List)) }; + }); - var o = JSON.ToObject(s); - Assert.AreEqual(ip.ip, o.ip); + var pt1 = new Point() { x = 1, y = 2.3f }; + var s = JSON.ToJSON(pt1); + Console.WriteLine(s); + var pt2 = JSON.ToObject(s); + Assert.AreEqual(pt1, pt2); + + var c1 = new Complex() { + i = 9, + l = new List() { + new Point[] { + new Point() { x = 1, y = 2.3f }, + new Point() { x = 2, y = 3.4f }, + }, + new Point[] { + new Point() { x = 5, y = 6.7f }, + }, + } + }; + s = JSON.ToJSON(c1); + Console.WriteLine(s); + var c2 = JSON.ToObject(s); + Assert.AreEqual(s, JSON.ToJSON(c2)); + + var d1 = new Dictionary>>() { + {"a", new List> { + new List { + new Point() { x = 1, y = 2.3f }, + new Point() { x = 2, y = 3.4f }, + }, + new List { + new Point() { x = 5, y = 6.7f }, + }, + }} + }; + s = JSON.ToJSON(d1); + Console.WriteLine(s); + var d2 = JSON.ToObject(s, d1.GetType()); + Assert.AreEqual(s, JSON.ToJSON(d2)); } [Test] diff --git a/fastJSON/JSON.cs b/fastJSON/JSON.cs index fc2434c..8cd3157 100644 --- a/fastJSON/JSON.cs +++ b/fastJSON/JSON.cs @@ -10,8 +10,9 @@ namespace fastJSON { + public delegate object DeserializeCallback(object data, Type type); public delegate string Serialize(object data); - public delegate object Deserialize(string data); + public delegate object Deserialize(object data, DeserializeCallback cb); public sealed class JSONParameters { @@ -382,6 +383,12 @@ public object ToObject(string json) } public object ToObject(string json, Type type) + { + object o = new JsonParser(json).Decode(); + return ToTyped(o, type); + } + + public object ToTyped(object o, Type type) { //_params = Parameters; _params.FixValues(); @@ -392,7 +399,9 @@ public object ToObject(string json, Type type) _params.UsingGlobalTypes = false; _usingglobals = _params.UsingGlobalTypes; - object o = new JsonParser(json).Decode(); + if ((type != null) && Reflection.Instance.IsTypeRegistered(type)) + return Reflection.Instance.CreateCustom(o, type, ToTyped); + if (o == null) return null; #if !SILVERLIGHT @@ -490,9 +499,6 @@ private object ChangeType(object value, Type conversionType) else if (conversionType == typeof(DateTimeOffset)) return CreateDateTimeOffset((string)value); - else if (Reflection.Instance.IsTypeRegistered(conversionType)) - return Reflection.Instance.CreateCustom((string)value, conversionType); - // 8-30-2014 - James Brooks - Added code for nullable types. if (IsNullable(conversionType)) { @@ -612,8 +618,17 @@ private void DoParseList(object parse, Type it, IList o) { _usingglobals = false; object v = k; - if (k is Dictionary) + if ((it != null) && Reflection.Instance.IsTypeRegistered(it)) + v = Reflection.Instance.CreateCustom(k, it, ToTyped); + else if (k is Dictionary) v = ParseDictionary(k as Dictionary, globals, it, null); + else if (k is List) + { + if (it != null && it.IsArray) + v = RootArray(k, it); + else + v = RootList(k, it); + } else v = ChangeType(k, it); @@ -682,6 +697,8 @@ internal object ParseDictionary(Dictionary d, Dictionary))) + return RootDictionary(d, type); if (d.TryGetValue("$i", out tn)) { @@ -789,7 +806,7 @@ internal object ParseDictionary(Dictionary d, Dictionary)v, pi.pt, pi.GenericTypes, globaltypes); break; case myPropInfoType.NameValue: oset = CreateNV((Dictionary)v); break; case myPropInfoType.StringDictionary: oset = CreateSD((Dictionary)v); break; - case myPropInfoType.Custom: oset = Reflection.Instance.CreateCustom((string)v, pi.pt); break; + case myPropInfoType.Custom: oset = Reflection.Instance.CreateCustom(v, pi.pt, ToTyped); break; default: { if (pi.IsGenericType && pi.IsValueType == false && v is List) @@ -997,13 +1014,12 @@ private object CreateGenericList(List data, Type pt, Type bt, Dictionary { if (ob is IDictionary) col.Add(ParseDictionary((Dictionary)ob, globalTypes, it, null)); - else if (ob is List) { - if (bt.IsGenericType) - col.Add((List)ob);//).ToArray()); + if (it.IsArray) + col.Add(RootArray(ob, it)); else - col.Add(((List)ob).ToArray()); + col.Add(RootList(ob, it)); } else col.Add(ChangeType(ob, it)); diff --git a/fastJSON/JsonSerializer.cs b/fastJSON/JsonSerializer.cs index 8aaebf8..9db0963 100644 --- a/fastJSON/JsonSerializer.cs +++ b/fastJSON/JsonSerializer.cs @@ -238,7 +238,7 @@ private void WriteCustom(object obj) { Serialize s; Reflection.Instance._customSerializer.TryGetValue(obj.GetType(), out s); - WriteStringFast(s(obj)); + WriteRaw(s(obj)); } private void WriteEnum(Enum e) @@ -686,5 +686,10 @@ private void WriteString(string s) _output.Append('\"'); } + + private void WriteRaw(string s) + { + _output.Append(s); + } } } diff --git a/fastJSON/Reflection.cs b/fastJSON/Reflection.cs index 42aac40..653b2dc 100644 --- a/fastJSON/Reflection.cs +++ b/fastJSON/Reflection.cs @@ -103,11 +103,11 @@ private Reflection() internal SafeDictionary _customSerializer = new SafeDictionary(); internal SafeDictionary _customDeserializer = new SafeDictionary(); - internal object CreateCustom(string v, Type type) + internal object CreateCustom(object v, Type type, DeserializeCallback cb) { Deserialize d; _customDeserializer.TryGetValue(type, out d); - return d(v); + return d(v, cb); } internal void RegisterCustomType(Type type, Serialize serializer, Deserialize deserializer) From f28725825af3be7ebbc51ddce5ef1d521b75c4ef Mon Sep 17 00:00:00 2001 From: enginekit Date: Mon, 30 Apr 2018 08:14:07 +0700 Subject: [PATCH 2/4] 01: update gitignore and unit packages --- .gitignore | 331 +++++++++++++++++++++++++++++++++++++ UnitTests/UnitTests.csproj | 19 ++- UnitTests/packages.config | 4 + 3 files changed, 353 insertions(+), 1 deletion(-) create mode 100644 .gitignore create mode 100644 UnitTests/packages.config diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0fcb27e --- /dev/null +++ b/.gitignore @@ -0,0 +1,331 @@ +################# +## Eclipse +################# + +*.pydevproject +.project +.metadata +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.classpath +.settings/ +.loadpath + +.vs/ + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# CDT-specific +.cproject + +# PDT-specific +.buildpath + + +################# +## Visual Studio +################# + +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +build/ +[Bb]in/ +[Oo]bj/ +output/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.Publish.xml +*.pubxml +*.publishproj + +# NuGet Packages Directory +## TODO: If you have NuGet Package Restore enabled, uncomment the next line +#packages/ + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.[Pp]ublish.xml +*.pfx +*.publishsettings + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file to a newer +# Visual Studio version. Backup files are not needed, because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + +############# +## Windows detritus +############# + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac crap +.DS_Store + + +############# +## Python +############# + +*.py[cod] + +# Packages +*.egg +*.egg-info +dist/ +build/ +eggs/ +parts/ +var/ +sdist/ +develop-eggs/ +.installed.cfg + +# Installer logs +pip-log.txt + +# Unit test / coverage reports +.coverage +.tox + +#Translations +*.mo + +#Mr Developer +.mr.developer.cfg +# Build Folders (you can keep bin if you'd like, to store dlls and pdbs) +[Bb]in/ +[Oo]bj/ + +# mstest test results +TestResults + +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results +[Dd]ebug/ +[Rr]elease/ +x64/ +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.log +*.vspscc +*.vssscc +.builds + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper* + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# Installshield output folder +[Ee]xpress + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish + +# Publish Web Output +*.Publish.xml + +# NuGet Packages Directory +packages + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +[Bb]in +[Oo]bj +sql +TestResults +[Tt]est[Rr]esult* +*.Cache +ClientBin +[Ss]tyle[Cc]op.* +~$* +*.dbmdl +Generated_Code #added for RIA/Silverlight projects + +# Backup & report files from converting an old project file to a newer +# Visual Studio version. Backup files are not needed, because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML + +*.DotSettings +clrdev.setting +.DS_Store \ No newline at end of file diff --git a/UnitTests/UnitTests.csproj b/UnitTests/UnitTests.csproj index ce328b1..b2e83c3 100644 --- a/UnitTests/UnitTests.csproj +++ b/UnitTests/UnitTests.csproj @@ -1,5 +1,6 @@  + Debug AnyCPU @@ -21,6 +22,8 @@ 3.5 ..\ true + + true @@ -44,10 +47,12 @@ - C:\Program Files (x86)\NUnit 2.6.4\bin\framework\nunit.framework.dll + + ..\packages\NUnit.3.10.1\lib\net40\nunit.framework.dll + @@ -63,7 +68,19 @@ fastJSON + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + +