From d32061cd1659203acacb8bca9e08d15c70d7d3d8 Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Wed, 7 Mar 2012 22:59:10 +1300 Subject: -Improved performance issue fix for deeply nested LINQ to JSON objects --- Src/Newtonsoft.Json.Tests/Linq/JArrayTests.cs | 9 +++++++++ Src/Newtonsoft.Json.Tests/PerformanceTests.cs | 17 +++++++++++++++- Src/Newtonsoft.Json/Linq/JContainer.cs | 29 +++++++++------------------ 3 files changed, 34 insertions(+), 21 deletions(-) diff --git a/Src/Newtonsoft.Json.Tests/Linq/JArrayTests.cs b/Src/Newtonsoft.Json.Tests/Linq/JArrayTests.cs index a25c7fc..dc6cd1b 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/JArrayTests.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/JArrayTests.cs @@ -20,6 +20,15 @@ namespace Newtonsoft.Json.Tests.Linq Assert.AreEqual(0, a.Count); } + [Test] + public void AddToSelf() + { + JArray a = new JArray(); + a.Add(a); + + Assert.IsFalse(ReferenceEquals(a[0], a)); + } + [Test] public void Contains() { diff --git a/Src/Newtonsoft.Json.Tests/PerformanceTests.cs b/Src/Newtonsoft.Json.Tests/PerformanceTests.cs index 57c9e8e..7d3b8bd 100644 --- a/Src/Newtonsoft.Json.Tests/PerformanceTests.cs +++ b/Src/Newtonsoft.Json.Tests/PerformanceTests.cs @@ -703,6 +703,21 @@ namespace Newtonsoft.Json.Tests }, "JObject.ToString"); } + [Test] + public void RecursiveLoop() + { + JArray a1 = new JArray(); + JArray a2 = new JArray(); + JArray a3 = new JArray(); + JArray a4 = new JArray(); + + a1.Add(a2); + a2.Add(a3); + a3.Add(a4); + + + } + [Test] public void NestedJToken() { @@ -716,7 +731,7 @@ namespace Newtonsoft.Json.Tests for (int j = 0; j < i; j++) { JArray temp = new JArray(); - ija.AddAndSkipParentCheck(temp); + ija.Add(temp); ija = temp; } ija.Add(1); diff --git a/Src/Newtonsoft.Json/Linq/JContainer.cs b/Src/Newtonsoft.Json/Linq/JContainer.cs index d1f83e0..ec992fe 100644 --- a/Src/Newtonsoft.Json/Linq/JContainer.cs +++ b/Src/Newtonsoft.Json/Linq/JContainer.cs @@ -266,27 +266,16 @@ namespace Newtonsoft.Json.Linq if (item == null) return new JValue((object) null); - if (item.Parent != null) - { + if (skipParentCheck) + return item; + + // to avoid a token having multiple parents or creating a recursive loop, create a copy if... + // the item already has a parent + // the item is being added to itself + // the item is being added to the root parent of itself + if (item.Parent != null || item == this || (item.HasValues && Root == item)) item = item.CloneToken(); - } - else - { - // check whether attempting to add a token to itself - // not possible with a value, only a container - if (item is JContainer && !skipParentCheck) - { - JContainer parent = this; - while (parent.Parent != null) - { - parent = parent.Parent; - } - if (item == parent) - { - item = item.CloneToken(); - } - } - } + return item; } -- cgit v1.2.3