-Rewrote LINQ to JSON internals to use lists and dictionaries rather than a linked list
-Moved JPropertyDescriptor to Newtonsoft.Json.Linq namespace
This commit is contained in:
@@ -29,7 +29,6 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using NUnit.Framework;
|
||||
using Newtonsoft.Json.Linq.ComponentModel;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Newtonsoft.Json.Tests.Linq.ComponentModel
|
||||
|
||||
@@ -165,7 +165,7 @@ Parameter name: arrayIndex")]
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(ArgumentOutOfRangeException), ExpectedMessage = @"index is equal to or greater than Count.
|
||||
[ExpectedException(typeof(ArgumentOutOfRangeException), ExpectedMessage = @"Index is equal to or greater than Count.
|
||||
Parameter name: index")]
|
||||
public void RemoveAtOutOfRangeIndexShouldError()
|
||||
{
|
||||
@@ -174,7 +174,7 @@ Parameter name: index")]
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(ArgumentOutOfRangeException), ExpectedMessage = @"index is less than 0.
|
||||
[ExpectedException(typeof(ArgumentOutOfRangeException), ExpectedMessage = @"Index is less than 0.
|
||||
Parameter name: index")]
|
||||
public void RemoveAtNegativeIndexShouldError()
|
||||
{
|
||||
@@ -253,7 +253,7 @@ Parameter name: index")]
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(ArgumentOutOfRangeException), ExpectedMessage = @"Specified argument was out of the range of valid values.
|
||||
[ExpectedException(typeof(ArgumentOutOfRangeException), ExpectedMessage = @"Index was out of range. Must be non-negative and less than the size of the collection.
|
||||
Parameter name: index")]
|
||||
public void InsertNegativeIndexShouldThrow()
|
||||
{
|
||||
@@ -262,7 +262,7 @@ Parameter name: index")]
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(ArgumentOutOfRangeException), ExpectedMessage = @"Specified argument was out of the range of valid values.
|
||||
[ExpectedException(typeof(ArgumentOutOfRangeException), ExpectedMessage = @"Index must be within the bounds of the List.
|
||||
Parameter name: index")]
|
||||
public void InsertOutOfRangeIndexShouldThrow()
|
||||
{
|
||||
|
||||
@@ -121,6 +121,31 @@ namespace Newtonsoft.Json.Tests
|
||||
return result;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BuildJObject()
|
||||
{
|
||||
JObject o = new JObject();
|
||||
for (int i = 0; i < 200; i++)
|
||||
{
|
||||
o[i.ToString()] = i;
|
||||
}
|
||||
string jsonText = o.ToString();
|
||||
|
||||
// this is extremely slow with 5000 interations
|
||||
int interations = 100;
|
||||
|
||||
TimeOperation(() =>
|
||||
{
|
||||
JObject oo = null;
|
||||
for (int i = 0; i < interations; i++)
|
||||
{
|
||||
oo = JObject.Parse(jsonText);
|
||||
}
|
||||
|
||||
return oo;
|
||||
}, "JObject");
|
||||
}
|
||||
|
||||
private void SerializeSize(object value)
|
||||
{
|
||||
// this is extremely slow with 5000 interations
|
||||
|
||||
@@ -41,5 +41,5 @@ using System.Runtime.InteropServices;
|
||||
// by using the '*' as shown below:
|
||||
[assembly: AssemblyVersion("4.0.2.0")]
|
||||
#if !PocketPC
|
||||
[assembly: AssemblyFileVersion("4.0.2.13722")]
|
||||
[assembly: AssemblyFileVersion("4.0.2.13728")]
|
||||
#endif
|
||||
|
||||
@@ -39,6 +39,13 @@ namespace Newtonsoft.Json.Linq
|
||||
/// </summary>
|
||||
public class JArray : JContainer, IList<JToken>
|
||||
{
|
||||
private IList<JToken> _values = new List<JToken>();
|
||||
|
||||
protected override IList<JToken> ChildrenTokens
|
||||
{
|
||||
get { return _values; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the node type for this <see cref="JToken"/>.
|
||||
/// </summary>
|
||||
|
||||
@@ -38,6 +38,12 @@ namespace Newtonsoft.Json.Linq
|
||||
public class JConstructor : JContainer
|
||||
{
|
||||
private string _name;
|
||||
private IList<JToken> _values = new List<JToken>();
|
||||
|
||||
protected override IList<JToken> ChildrenTokens
|
||||
{
|
||||
get { return _values; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of this constructor.
|
||||
|
||||
@@ -33,9 +33,6 @@ using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.ComponentModel;
|
||||
using System.Collections.Specialized;
|
||||
#if !SILVERLIGHT
|
||||
using Newtonsoft.Json.Linq.ComponentModel;
|
||||
#endif
|
||||
|
||||
namespace Newtonsoft.Json.Linq
|
||||
{
|
||||
@@ -70,16 +67,11 @@ namespace Newtonsoft.Json.Linq
|
||||
public event NotifyCollectionChangedEventHandler CollectionChanged;
|
||||
#endif
|
||||
|
||||
private JToken _content;
|
||||
protected abstract IList<JToken> ChildrenTokens { get; }
|
||||
|
||||
private object _syncRoot;
|
||||
private bool _busy;
|
||||
|
||||
internal JToken Content
|
||||
{
|
||||
get { return _content; }
|
||||
set { _content = value; }
|
||||
}
|
||||
|
||||
internal JContainer()
|
||||
{
|
||||
}
|
||||
@@ -88,15 +80,9 @@ namespace Newtonsoft.Json.Linq
|
||||
{
|
||||
ValidationUtils.ArgumentNotNull(other, "c");
|
||||
|
||||
JToken content = other.Last;
|
||||
if (content != null)
|
||||
foreach (JToken child in other)
|
||||
{
|
||||
do
|
||||
{
|
||||
content = content._next;
|
||||
Add(content.CloneToken());
|
||||
}
|
||||
while (content != other.Last);
|
||||
Add(child);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,7 +158,7 @@ namespace Newtonsoft.Json.Linq
|
||||
/// </value>
|
||||
public override bool HasValues
|
||||
{
|
||||
get { return (_content != null); }
|
||||
get { return ChildrenTokens.Count > 0; }
|
||||
}
|
||||
|
||||
internal bool ContentsEqual(JContainer container)
|
||||
@@ -209,13 +195,7 @@ namespace Newtonsoft.Json.Linq
|
||||
/// </value>
|
||||
public override JToken First
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Last == null)
|
||||
return null;
|
||||
|
||||
return Last._next;
|
||||
}
|
||||
get { return ChildrenTokens.FirstOrDefault(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -226,8 +206,7 @@ namespace Newtonsoft.Json.Linq
|
||||
/// </value>
|
||||
public override JToken Last
|
||||
{
|
||||
[DebuggerStepThrough]
|
||||
get { return _content; }
|
||||
get { return ChildrenTokens.LastOrDefault(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -238,21 +217,7 @@ namespace Newtonsoft.Json.Linq
|
||||
/// </returns>
|
||||
public override JEnumerable<JToken> Children()
|
||||
{
|
||||
return new JEnumerable<JToken>(ChildrenInternal());
|
||||
}
|
||||
|
||||
internal IEnumerable<JToken> ChildrenInternal()
|
||||
{
|
||||
JToken first = First;
|
||||
JToken current = first;
|
||||
if (current == null)
|
||||
yield break;
|
||||
|
||||
do
|
||||
{
|
||||
yield return current;
|
||||
}
|
||||
while ((current = current.Next) != null);
|
||||
return new JEnumerable<JToken>(ChildrenTokens);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -264,7 +229,7 @@ namespace Newtonsoft.Json.Linq
|
||||
/// </returns>
|
||||
public override IEnumerable<T> Values<T>()
|
||||
{
|
||||
return Children().Convert<JToken, T>();
|
||||
return ChildrenTokens.Convert<JToken, T>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -273,7 +238,7 @@ namespace Newtonsoft.Json.Linq
|
||||
/// <returns>An <see cref="IEnumerable{JToken}"/> containing the descendant tokens of the <see cref="JToken"/>.</returns>
|
||||
public IEnumerable<JToken> Descendants()
|
||||
{
|
||||
foreach (JToken o in Children())
|
||||
foreach (JToken o in ChildrenTokens)
|
||||
{
|
||||
yield return o;
|
||||
JContainer c = o as JContainer;
|
||||
@@ -292,37 +257,11 @@ namespace Newtonsoft.Json.Linq
|
||||
return (content is IEnumerable && !(content is string) && !(content is JToken) && !(content is byte[]));
|
||||
}
|
||||
|
||||
internal virtual void AddItem(bool isLast, JToken previous, JToken item)
|
||||
{
|
||||
CheckReentrancy();
|
||||
|
||||
ValidateToken(item, null);
|
||||
|
||||
item = EnsureParentToken(item);
|
||||
|
||||
JToken next = (previous != null) ? previous._next : item;
|
||||
|
||||
item.Parent = this;
|
||||
item.Next = next;
|
||||
|
||||
if (previous != null)
|
||||
previous.Next = item;
|
||||
|
||||
if (isLast || previous == null)
|
||||
_content = item;
|
||||
|
||||
#if !SILVERLIGHT
|
||||
if (ListChanged != null)
|
||||
OnListChanged(new ListChangedEventArgs(ListChangedType.ItemAdded, IndexOfItem(item)));
|
||||
#endif
|
||||
#if SILVERLIGHT || !(NET20 || NET35)
|
||||
if (CollectionChanged != null)
|
||||
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, IndexOfItem(item)));
|
||||
#endif
|
||||
}
|
||||
|
||||
internal JToken EnsureParentToken(JToken item)
|
||||
{
|
||||
if (item == null)
|
||||
return new JValue((object) null);
|
||||
|
||||
if (item.Parent != null)
|
||||
{
|
||||
item = item.CloneToken();
|
||||
@@ -343,142 +282,157 @@ namespace Newtonsoft.Json.Linq
|
||||
return item;
|
||||
}
|
||||
|
||||
internal void AddInternal(bool isLast, JToken previous, object content)
|
||||
private class JTokenReferenceEqualityComparer : IEqualityComparer<JToken>
|
||||
{
|
||||
if (IsMultiContent(content))
|
||||
{
|
||||
IEnumerable enumerable = (IEnumerable) content;
|
||||
public static readonly JTokenReferenceEqualityComparer Instance = new JTokenReferenceEqualityComparer();
|
||||
|
||||
JToken multiPrevious = previous;
|
||||
foreach (object c in enumerable)
|
||||
{
|
||||
AddInternal(isLast, multiPrevious, c);
|
||||
multiPrevious = (multiPrevious != null) ? multiPrevious._next : Last;
|
||||
}
|
||||
public bool Equals(JToken x, JToken y)
|
||||
{
|
||||
return ReferenceEquals(x, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
JToken item = CreateFromContent(content);
|
||||
|
||||
AddItem(isLast, previous, item);
|
||||
public int GetHashCode(JToken obj)
|
||||
{
|
||||
if (obj == null)
|
||||
return 0;
|
||||
|
||||
return obj.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
internal int IndexOfItem(JToken item)
|
||||
{
|
||||
int index = 0;
|
||||
foreach (JToken token in Children())
|
||||
{
|
||||
if (token == item)
|
||||
return index;
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
return -1;
|
||||
return ChildrenTokens.IndexOf(item, JTokenReferenceEqualityComparer.Instance);
|
||||
}
|
||||
|
||||
internal virtual void InsertItem(int index, JToken item)
|
||||
{
|
||||
if (index == 0)
|
||||
{
|
||||
AddFirst(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
JToken token = GetItem(index);
|
||||
AddInternal(false, token.Previous, item);
|
||||
}
|
||||
if (index > ChildrenTokens.Count)
|
||||
throw new ArgumentOutOfRangeException("index", "Index must be within the bounds of the List.");
|
||||
|
||||
CheckReentrancy();
|
||||
|
||||
item = EnsureParentToken(item);
|
||||
|
||||
JToken previous = (index == 0) ? null : ChildrenTokens[index - 1];
|
||||
// haven't inserted new token yet so next token is still at the inserting index
|
||||
JToken next = (index == ChildrenTokens.Count) ? null : ChildrenTokens[index];
|
||||
|
||||
ValidateToken(item, null);
|
||||
|
||||
item.Parent = this;
|
||||
|
||||
item.Previous = previous;
|
||||
if (previous != null)
|
||||
previous.Next = item;
|
||||
|
||||
item.Next = next;
|
||||
if (next != null)
|
||||
next.Previous = item;
|
||||
|
||||
ChildrenTokens.Insert(index, item);
|
||||
|
||||
#if !SILVERLIGHT
|
||||
if (ListChanged != null)
|
||||
OnListChanged(new ListChangedEventArgs(ListChangedType.ItemAdded, index));
|
||||
#endif
|
||||
#if SILVERLIGHT || !(NET20 || NET35)
|
||||
if (CollectionChanged != null)
|
||||
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, index));
|
||||
#endif
|
||||
}
|
||||
|
||||
internal virtual void RemoveItemAt(int index)
|
||||
{
|
||||
if (index < 0)
|
||||
throw new ArgumentOutOfRangeException("index", "index is less than 0.");
|
||||
throw new ArgumentOutOfRangeException("index", "Index is less than 0.");
|
||||
if (index >= ChildrenTokens.Count)
|
||||
throw new ArgumentOutOfRangeException("index", "Index is equal to or greater than Count.");
|
||||
|
||||
CheckReentrancy();
|
||||
|
||||
int currentIndex = 0;
|
||||
foreach (JToken token in Children())
|
||||
{
|
||||
if (index == currentIndex)
|
||||
{
|
||||
token.Remove();
|
||||
JToken item = ChildrenTokens[index];
|
||||
JToken previous = (index == 0) ? null : ChildrenTokens[index - 1];
|
||||
JToken next = (index == ChildrenTokens.Count - 1) ? null : ChildrenTokens[index + 1];
|
||||
|
||||
if (previous != null)
|
||||
previous.Next = next;
|
||||
if (next != null)
|
||||
next.Previous = previous;
|
||||
|
||||
item.Parent = null;
|
||||
item.Previous = null;
|
||||
item.Next = null;
|
||||
|
||||
ChildrenTokens.RemoveAt(index);
|
||||
|
||||
#if !SILVERLIGHT
|
||||
OnListChanged(new ListChangedEventArgs(ListChangedType.ItemDeleted, index));
|
||||
OnListChanged(new ListChangedEventArgs(ListChangedType.ItemDeleted, index));
|
||||
#endif
|
||||
#if SILVERLIGHT || !(NET20 || NET35)
|
||||
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, token, index));
|
||||
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item, index));
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
currentIndex++;
|
||||
}
|
||||
|
||||
throw new ArgumentOutOfRangeException("index", "index is equal to or greater than Count.");
|
||||
}
|
||||
|
||||
internal virtual bool RemoveItem(JToken item)
|
||||
{
|
||||
if (item == null || item.Parent != this)
|
||||
return false;
|
||||
|
||||
CheckReentrancy();
|
||||
|
||||
JToken content = _content;
|
||||
|
||||
int itemIndex = 0;
|
||||
while (content._next != item)
|
||||
int index = IndexOfItem(item);
|
||||
if (index >= 0)
|
||||
{
|
||||
itemIndex++;
|
||||
content = content._next;
|
||||
RemoveItemAt(index);
|
||||
return true;
|
||||
}
|
||||
if (content == item)
|
||||
{
|
||||
// token is containers last child
|
||||
_content = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_content == item)
|
||||
{
|
||||
_content = content;
|
||||
}
|
||||
content._next = item._next;
|
||||
}
|
||||
item.Parent = null;
|
||||
item.Next = null;
|
||||
|
||||
#if !SILVERLIGHT
|
||||
OnListChanged(new ListChangedEventArgs(ListChangedType.ItemDeleted, itemIndex));
|
||||
#endif
|
||||
#if SILVERLIGHT || !(NET20 || NET35)
|
||||
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item, itemIndex));
|
||||
#endif
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
internal virtual JToken GetItem(int index)
|
||||
{
|
||||
return Children().ElementAt(index);
|
||||
return ChildrenTokens[index];
|
||||
}
|
||||
|
||||
internal virtual void SetItem(int index, JToken item)
|
||||
{
|
||||
if (index < 0)
|
||||
throw new ArgumentOutOfRangeException("index", "Index is less than 0.");
|
||||
if (index >= ChildrenTokens.Count)
|
||||
throw new ArgumentOutOfRangeException("index", "Index is equal to or greater than Count.");
|
||||
|
||||
JToken existing = ChildrenTokens[index];
|
||||
|
||||
if (IsTokenUnchanged(existing, item))
|
||||
return;
|
||||
|
||||
CheckReentrancy();
|
||||
|
||||
JToken token = GetItem(index);
|
||||
token.Replace(item);
|
||||
item = EnsureParentToken(item);
|
||||
|
||||
ValidateToken(item, existing);
|
||||
|
||||
JToken previous = (index == 0) ? null : ChildrenTokens[index - 1];
|
||||
JToken next = (index == ChildrenTokens.Count - 1) ? null : ChildrenTokens[index + 1];
|
||||
|
||||
item.Parent = this;
|
||||
|
||||
item.Previous = previous;
|
||||
if (previous != null)
|
||||
previous.Next = item;
|
||||
|
||||
item.Next = next;
|
||||
if (next != null)
|
||||
next.Previous = item;
|
||||
|
||||
ChildrenTokens[index] = item;
|
||||
|
||||
existing.Parent = null;
|
||||
existing.Previous = null;
|
||||
existing.Next = null;
|
||||
|
||||
#if !SILVERLIGHT
|
||||
OnListChanged(new ListChangedEventArgs(ListChangedType.ItemChanged, index));
|
||||
#endif
|
||||
#if SILVERLIGHT || !(NET20 || NET35)
|
||||
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, item, token, index));
|
||||
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, item, existing, index));
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -486,23 +440,15 @@ namespace Newtonsoft.Json.Linq
|
||||
{
|
||||
CheckReentrancy();
|
||||
|
||||
while (_content != null)
|
||||
foreach (JToken item in ChildrenTokens)
|
||||
{
|
||||
JToken o = _content;
|
||||
|
||||
JToken next = o._next;
|
||||
if (o != _content || next != o._next)
|
||||
throw new InvalidOperationException("This operation was corrupted by external code.");
|
||||
|
||||
if (next != o)
|
||||
o._next = next._next;
|
||||
else
|
||||
_content = null;
|
||||
|
||||
next.Parent = null;
|
||||
next._next = null;
|
||||
item.Parent = null;
|
||||
item.Previous = null;
|
||||
item.Next = null;
|
||||
}
|
||||
|
||||
ChildrenTokens.Clear();
|
||||
|
||||
#if !SILVERLIGHT
|
||||
OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
|
||||
#endif
|
||||
@@ -516,51 +462,8 @@ namespace Newtonsoft.Json.Linq
|
||||
if (existing == null || existing.Parent != this)
|
||||
return;
|
||||
|
||||
if (IsTokenUnchanged(existing, replacement))
|
||||
return;
|
||||
|
||||
CheckReentrancy();
|
||||
|
||||
replacement = EnsureParentToken(replacement);
|
||||
|
||||
ValidateToken(replacement, existing);
|
||||
|
||||
JToken content = _content;
|
||||
|
||||
int itemIndex = 0;
|
||||
while (content._next != existing)
|
||||
{
|
||||
itemIndex++;
|
||||
content = content._next;
|
||||
}
|
||||
|
||||
if (content == existing)
|
||||
{
|
||||
// token is containers last child
|
||||
_content = replacement;
|
||||
replacement._next = replacement;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_content == existing)
|
||||
{
|
||||
_content = replacement;
|
||||
}
|
||||
content._next = replacement;
|
||||
replacement._next = existing._next;
|
||||
}
|
||||
|
||||
replacement.Parent = this;
|
||||
|
||||
existing.Parent = null;
|
||||
existing.Next = null;
|
||||
|
||||
#if !SILVERLIGHT
|
||||
OnListChanged(new ListChangedEventArgs(ListChangedType.ItemChanged, itemIndex));
|
||||
#endif
|
||||
#if SILVERLIGHT || !(NET20 || NET35)
|
||||
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, replacement, existing, itemIndex));
|
||||
#endif
|
||||
int index = IndexOfItem(existing);
|
||||
SetItem(index, replacement);
|
||||
}
|
||||
|
||||
internal virtual bool ContainsItem(JToken item)
|
||||
@@ -580,7 +483,7 @@ namespace Newtonsoft.Json.Linq
|
||||
throw new ArgumentException("The number of elements in the source JObject is greater than the available space from arrayIndex to the end of the destination array.");
|
||||
|
||||
int index = 0;
|
||||
foreach (JToken token in Children())
|
||||
foreach (JToken token in ChildrenTokens)
|
||||
{
|
||||
array.SetValue(token, arrayIndex + index);
|
||||
index++;
|
||||
@@ -589,7 +492,7 @@ namespace Newtonsoft.Json.Linq
|
||||
|
||||
internal virtual int CountItems()
|
||||
{
|
||||
return Children().Count();
|
||||
return ChildrenTokens.Count;
|
||||
}
|
||||
|
||||
internal static bool IsTokenUnchanged(JToken currentValue, JToken newValue)
|
||||
@@ -619,9 +522,9 @@ namespace Newtonsoft.Json.Linq
|
||||
/// Adds the specified content as children of this <see cref="JToken"/>.
|
||||
/// </summary>
|
||||
/// <param name="content">The content to be added.</param>
|
||||
public void Add(object content)
|
||||
public virtual void Add(object content)
|
||||
{
|
||||
AddInternal(true, Last, content);
|
||||
AddInternal(ChildrenTokens.Count, content);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -630,7 +533,28 @@ namespace Newtonsoft.Json.Linq
|
||||
/// <param name="content">The content to be added.</param>
|
||||
public void AddFirst(object content)
|
||||
{
|
||||
AddInternal(false, Last, content);
|
||||
AddInternal(0, content);
|
||||
}
|
||||
|
||||
internal void AddInternal(int index, object content)
|
||||
{
|
||||
if (IsMultiContent(content))
|
||||
{
|
||||
IEnumerable enumerable = (IEnumerable)content;
|
||||
|
||||
int multiIndex = index;
|
||||
foreach (object c in enumerable)
|
||||
{
|
||||
AddInternal(multiIndex, c);
|
||||
multiIndex++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
JToken item = CreateFromContent(content);
|
||||
|
||||
InsertItem(index, item);
|
||||
}
|
||||
}
|
||||
|
||||
internal JToken CreateFromContent(object content)
|
||||
@@ -790,7 +714,7 @@ namespace Newtonsoft.Json.Linq
|
||||
internal int ContentsHashCode()
|
||||
{
|
||||
int hashCode = 0;
|
||||
foreach (JToken item in Children())
|
||||
foreach (JToken item in ChildrenTokens)
|
||||
{
|
||||
hashCode ^= item.GetDeepHashCode();
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
#if !(NET35 || NET20 || WINDOWS_PHONE)
|
||||
@@ -35,9 +36,6 @@ using System.Linq;
|
||||
using System.IO;
|
||||
using Newtonsoft.Json.Utilities;
|
||||
using System.Globalization;
|
||||
#if !PocketPC && !SILVERLIGHT
|
||||
using Newtonsoft.Json.Linq.ComponentModel;
|
||||
#endif
|
||||
|
||||
namespace Newtonsoft.Json.Linq
|
||||
{
|
||||
@@ -52,6 +50,46 @@ namespace Newtonsoft.Json.Linq
|
||||
, INotifyPropertyChanging
|
||||
#endif
|
||||
{
|
||||
private class JPropertKeyedCollection : KeyedCollection<string, JToken>
|
||||
{
|
||||
public JPropertKeyedCollection(IEqualityComparer<string> comparer)
|
||||
: base(comparer)
|
||||
{
|
||||
}
|
||||
|
||||
protected override string GetKeyForItem(JToken item)
|
||||
{
|
||||
return ((JProperty) item).Name;
|
||||
}
|
||||
|
||||
protected override void InsertItem(int index, JToken item)
|
||||
{
|
||||
if (Dictionary == null)
|
||||
{
|
||||
base.InsertItem(index, item);
|
||||
}
|
||||
else
|
||||
{
|
||||
// need to override so that the dictionary key is always set rather than added
|
||||
string keyForItem = GetKeyForItem(item);
|
||||
Dictionary[keyForItem] = item;
|
||||
Items.Insert(index, item);
|
||||
}
|
||||
}
|
||||
|
||||
public new IDictionary<string, JToken> Dictionary
|
||||
{
|
||||
get { return base.Dictionary; }
|
||||
}
|
||||
}
|
||||
|
||||
private JPropertKeyedCollection _properties = new JPropertKeyedCollection(StringComparer.Ordinal);
|
||||
|
||||
protected override IList<JToken> ChildrenTokens
|
||||
{
|
||||
get { return _properties; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a property value changes.
|
||||
/// </summary>
|
||||
@@ -111,14 +149,18 @@ namespace Newtonsoft.Json.Linq
|
||||
if (o.Type != JTokenType.Property)
|
||||
throw new ArgumentException("Can not add {0} to {1}.".FormatWith(CultureInfo.InvariantCulture, o.GetType(), GetType()));
|
||||
|
||||
// looping over all properties every time isn't good
|
||||
// need to think about performance here
|
||||
JProperty property = (JProperty)o;
|
||||
foreach (JProperty childProperty in Children())
|
||||
JProperty newProperty = (JProperty) o;
|
||||
|
||||
if (existing != null)
|
||||
{
|
||||
if (childProperty != existing && string.Equals(childProperty.Name, property.Name, StringComparison.Ordinal))
|
||||
throw new ArgumentException("Can not add property {0} to {1}. Property with the same name already exists on object.".FormatWith(CultureInfo.InvariantCulture, property.Name, GetType()));
|
||||
JProperty existingProperty = (JProperty) existing;
|
||||
|
||||
if (newProperty.Name == existingProperty.Name)
|
||||
return;
|
||||
}
|
||||
|
||||
if (_properties.Dictionary != null && _properties.Dictionary.TryGetValue(newProperty.Name, out existing))
|
||||
throw new ArgumentException("Can not add property {0} to {1}. Property with the same name already exists on object.".FormatWith(CultureInfo.InvariantCulture, newProperty.Name, GetType()));
|
||||
}
|
||||
|
||||
internal void InternalPropertyChanged(JProperty childProperty)
|
||||
@@ -159,7 +201,7 @@ namespace Newtonsoft.Json.Linq
|
||||
/// <returns>An <see cref="IEnumerable{JProperty}"/> of this object's properties.</returns>
|
||||
public IEnumerable<JProperty> Properties()
|
||||
{
|
||||
return Children().Cast<JProperty>();
|
||||
return ChildrenTokens.Cast<JProperty>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -169,9 +211,14 @@ namespace Newtonsoft.Json.Linq
|
||||
/// <returns>A <see cref="JProperty"/> with the specified name or null.</returns>
|
||||
public JProperty Property(string name)
|
||||
{
|
||||
return Properties()
|
||||
.Where(p => string.Equals(p.Name, name, StringComparison.Ordinal))
|
||||
.SingleOrDefault();
|
||||
if (_properties.Dictionary == null)
|
||||
return null;
|
||||
if (name == null)
|
||||
return null;
|
||||
|
||||
JToken property;
|
||||
_properties.Dictionary.TryGetValue(name, out property);
|
||||
return (JProperty)property;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -318,7 +365,7 @@ namespace Newtonsoft.Json.Linq
|
||||
{
|
||||
writer.WriteStartObject();
|
||||
|
||||
foreach (JProperty property in ChildrenInternal())
|
||||
foreach (JProperty property in ChildrenTokens)
|
||||
{
|
||||
property.WriteTo(writer, converters);
|
||||
}
|
||||
@@ -339,12 +386,12 @@ namespace Newtonsoft.Json.Linq
|
||||
|
||||
bool IDictionary<string, JToken>.ContainsKey(string key)
|
||||
{
|
||||
return (Property(key) != null);
|
||||
return _properties.Dictionary.ContainsKey(key);
|
||||
}
|
||||
|
||||
ICollection<string> IDictionary<string, JToken>.Keys
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
get { return _properties.Dictionary.Keys; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -383,7 +430,7 @@ namespace Newtonsoft.Json.Linq
|
||||
|
||||
ICollection<JToken> IDictionary<string, JToken>.Values
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
get { return _properties.Dictionary.Values; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -421,7 +468,7 @@ namespace Newtonsoft.Json.Linq
|
||||
throw new ArgumentException("The number of elements in the source JObject is greater than the available space from arrayIndex to the end of the destination array.");
|
||||
|
||||
int index = 0;
|
||||
foreach (JProperty property in Properties())
|
||||
foreach (JProperty property in ChildrenTokens)
|
||||
{
|
||||
array[arrayIndex + index] = new KeyValuePair<string, JToken>(property.Name, property.Value);
|
||||
index++;
|
||||
@@ -467,7 +514,7 @@ namespace Newtonsoft.Json.Linq
|
||||
/// </returns>
|
||||
public IEnumerator<KeyValuePair<string, JToken>> GetEnumerator()
|
||||
{
|
||||
foreach (JProperty property in Properties())
|
||||
foreach (JProperty property in ChildrenTokens)
|
||||
{
|
||||
yield return new KeyValuePair<string, JToken>(property.Name, property.Value);
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
@@ -39,8 +40,14 @@ namespace Newtonsoft.Json.Linq
|
||||
/// </summary>
|
||||
public class JProperty : JContainer
|
||||
{
|
||||
private readonly List<JToken> _content = new List<JToken>();
|
||||
private readonly string _name;
|
||||
|
||||
protected override IList<JToken> ChildrenTokens
|
||||
{
|
||||
get { return _content; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the property name.
|
||||
/// </summary>
|
||||
@@ -58,42 +65,24 @@ namespace Newtonsoft.Json.Linq
|
||||
public JToken Value
|
||||
{
|
||||
[DebuggerStepThrough]
|
||||
get { return Content; }
|
||||
get { return (ChildrenTokens.Count > 0) ? ChildrenTokens[0] : null; }
|
||||
set
|
||||
{
|
||||
CheckReentrancy();
|
||||
|
||||
JToken newValue = value ?? new JValue((object) null);
|
||||
|
||||
if (Content == null)
|
||||
if (ChildrenTokens.Count == 0)
|
||||
{
|
||||
newValue = EnsureParentToken(newValue);
|
||||
|
||||
Content = newValue;
|
||||
Content.Parent = this;
|
||||
Content.Next = Content;
|
||||
InsertItem(0, newValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
Content.Replace(newValue);
|
||||
SetItem(0, newValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal override void ReplaceItem(JToken existing, JToken replacement)
|
||||
{
|
||||
if (IsTokenUnchanged(existing, replacement))
|
||||
return;
|
||||
|
||||
if (Parent != null)
|
||||
((JObject)Parent).InternalPropertyChanging(this);
|
||||
|
||||
base.ReplaceItem(existing, replacement);
|
||||
|
||||
if (Parent != null)
|
||||
((JObject)Parent).InternalPropertyChanged(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="JProperty"/> class from another <see cref="JProperty"/> object.
|
||||
/// </summary>
|
||||
@@ -104,14 +93,6 @@ namespace Newtonsoft.Json.Linq
|
||||
_name = other.Name;
|
||||
}
|
||||
|
||||
internal override void AddItem(bool isLast, JToken previous, JToken item)
|
||||
{
|
||||
if (Value != null)
|
||||
throw new Exception("{0} cannot have multiple values.".FormatWith(CultureInfo.InvariantCulture, typeof(JProperty)));
|
||||
|
||||
Value = item;
|
||||
}
|
||||
|
||||
internal override JToken GetItem(int index)
|
||||
{
|
||||
if (index != 0)
|
||||
@@ -124,8 +105,17 @@ namespace Newtonsoft.Json.Linq
|
||||
{
|
||||
if (index != 0)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
|
||||
Value = item;
|
||||
|
||||
if (IsTokenUnchanged(Value, item))
|
||||
return;
|
||||
|
||||
if (Parent != null)
|
||||
((JObject)Parent).InternalPropertyChanging(this);
|
||||
|
||||
base.SetItem(0, item);
|
||||
|
||||
if (Parent != null)
|
||||
((JObject)Parent).InternalPropertyChanged(this);
|
||||
}
|
||||
|
||||
internal override bool RemoveItem(JToken item)
|
||||
@@ -140,7 +130,10 @@ namespace Newtonsoft.Json.Linq
|
||||
|
||||
internal override void InsertItem(int index, JToken item)
|
||||
{
|
||||
throw new Exception("Cannot add or remove items from {0}.".FormatWith(CultureInfo.InvariantCulture, typeof(JProperty)));
|
||||
if (Value != null)
|
||||
throw new Exception("{0} cannot have multiple values.".FormatWith(CultureInfo.InvariantCulture, typeof(JProperty)));
|
||||
|
||||
base.InsertItem(0, item);
|
||||
}
|
||||
|
||||
internal override bool ContainsItem(JToken item)
|
||||
@@ -153,22 +146,6 @@ namespace Newtonsoft.Json.Linq
|
||||
throw new Exception("Cannot add or remove items from {0}.".FormatWith(CultureInfo.InvariantCulture, typeof(JProperty)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a collection of the child tokens of this token, in document order.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// An <see cref="IEnumerable{T}"/> of <see cref="JToken"/> containing the child tokens of this <see cref="JToken"/>, in document order.
|
||||
/// </returns>
|
||||
public override JEnumerable<JToken> Children()
|
||||
{
|
||||
return new JEnumerable<JToken>(GetValueEnumerable());
|
||||
}
|
||||
|
||||
private IEnumerable<JToken> GetValueEnumerable()
|
||||
{
|
||||
yield return Value;
|
||||
}
|
||||
|
||||
internal override bool DeepEquals(JToken node)
|
||||
{
|
||||
JProperty t = node as JProperty;
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@ using System;
|
||||
using System.ComponentModel;
|
||||
using Newtonsoft.Json.Utilities;
|
||||
|
||||
namespace Newtonsoft.Json.Linq.ComponentModel
|
||||
namespace Newtonsoft.Json.Linq
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a view of a <see cref="JProperty"/>.
|
||||
@@ -51,7 +51,8 @@ namespace Newtonsoft.Json.Linq
|
||||
#endif
|
||||
{
|
||||
private JContainer _parent;
|
||||
internal JToken _next;
|
||||
private JToken _previous;
|
||||
private JToken _next;
|
||||
private static JTokenEqualityComparer _equalityComparer;
|
||||
|
||||
private int? _lineNumber;
|
||||
@@ -138,13 +139,7 @@ namespace Newtonsoft.Json.Linq
|
||||
/// <value>The <see cref="JToken"/> that contains the next sibling token.</value>
|
||||
public JToken Next
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_parent != null && _next != _parent.First)
|
||||
return _next;
|
||||
|
||||
return null;
|
||||
}
|
||||
get { return _next; }
|
||||
internal set { _next = value; }
|
||||
}
|
||||
|
||||
@@ -154,20 +149,8 @@ namespace Newtonsoft.Json.Linq
|
||||
/// <value>The <see cref="JToken"/> that contains the previous sibling token.</value>
|
||||
public JToken Previous
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_parent == null)
|
||||
return null;
|
||||
|
||||
JToken parentNext = _parent.Content._next;
|
||||
JToken parentNextBefore = null;
|
||||
while (parentNext != this)
|
||||
{
|
||||
parentNextBefore = parentNext;
|
||||
parentNext = parentNext.Next;
|
||||
}
|
||||
return parentNextBefore;
|
||||
}
|
||||
get { return _previous; }
|
||||
internal set { _previous = value; }
|
||||
}
|
||||
|
||||
internal JToken()
|
||||
@@ -183,7 +166,8 @@ namespace Newtonsoft.Json.Linq
|
||||
if (_parent == null)
|
||||
throw new InvalidOperationException("The parent is missing.");
|
||||
|
||||
_parent.AddInternal((Next == null), this, content);
|
||||
int index = _parent.IndexOfItem(this);
|
||||
_parent.AddInternal(index + 1, content);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -195,11 +179,8 @@ namespace Newtonsoft.Json.Linq
|
||||
if (_parent == null)
|
||||
throw new InvalidOperationException("The parent is missing.");
|
||||
|
||||
JToken previous = Previous;
|
||||
if (previous == null)
|
||||
previous = _parent.Last;
|
||||
|
||||
_parent.AddInternal(false, previous, content);
|
||||
int index = _parent.IndexOfItem(this);
|
||||
_parent.AddInternal(index, content);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -96,8 +96,8 @@
|
||||
<Compile Include="Converters\RegexConverter.cs" />
|
||||
<Compile Include="Converters\StringEnumConverter.cs" />
|
||||
<Compile Include="JsonConstructorAttribute.cs" />
|
||||
<Compile Include="Linq\ComponentModel\JPropertyDescriptor.cs" />
|
||||
<Compile Include="Linq\JPath.cs" />
|
||||
<Compile Include="Linq\JPropertyDescriptor.cs" />
|
||||
<Compile Include="Linq\JRaw.cs" />
|
||||
<Compile Include="Required.cs" />
|
||||
<Compile Include="Serialization\DefaultReferenceResolver.cs" />
|
||||
|
||||
@@ -104,6 +104,7 @@
|
||||
<Compile Include="Converters\StringEnumConverter.cs" />
|
||||
<Compile Include="ConstructorHandling.cs" />
|
||||
<Compile Include="JsonConstructorAttribute.cs" />
|
||||
<Compile Include="Linq\JPropertyDescriptor.cs" />
|
||||
<Compile Include="Utilities\DynamicProxy.cs" />
|
||||
<Compile Include="Linq\JPath.cs" />
|
||||
<Compile Include="Linq\JRaw.cs" />
|
||||
@@ -115,7 +116,6 @@
|
||||
<Compile Include="Serialization\JsonPrimitiveContract.cs" />
|
||||
<Compile Include="Serialization\DynamicValueProvider.cs" />
|
||||
<Compile Include="Serialization\ErrorEventArgs.cs" />
|
||||
<Compile Include="Linq\ComponentModel\JPropertyDescriptor.cs" />
|
||||
<Compile Include="Serialization\DefaultReferenceResolver.cs" />
|
||||
<Compile Include="PreserveReferencesHandling.cs" />
|
||||
<Compile Include="IJsonLineInfo.cs" />
|
||||
|
||||
@@ -127,7 +127,6 @@
|
||||
<Compile Include="JsonValidatingReader.cs" />
|
||||
<Compile Include="JsonWriter.cs" />
|
||||
<Compile Include="JsonWriterException.cs" />
|
||||
<Compile Include="Linq\ComponentModel\JPropertyDescriptor.cs" />
|
||||
<Compile Include="Linq\Extensions.cs" />
|
||||
<Compile Include="Linq\IJEnumerable.cs" />
|
||||
<Compile Include="Linq\JArray.cs" />
|
||||
@@ -137,6 +136,7 @@
|
||||
<Compile Include="Linq\JObject.cs" />
|
||||
<Compile Include="Linq\JPath.cs" />
|
||||
<Compile Include="Linq\JProperty.cs" />
|
||||
<Compile Include="Linq\JPropertyDescriptor.cs" />
|
||||
<Compile Include="Linq\JRaw.cs" />
|
||||
<Compile Include="Linq\JToken.cs" />
|
||||
<Compile Include="Linq\JTokenEqualityComparer.cs" />
|
||||
|
||||
@@ -100,7 +100,6 @@
|
||||
<Compile Include="JsonValidatingReader.cs" />
|
||||
<Compile Include="JsonWriter.cs" />
|
||||
<Compile Include="JsonWriterException.cs" />
|
||||
<Compile Include="Linq\ComponentModel\JPropertyDescriptor.cs" />
|
||||
<Compile Include="Linq\Extensions.cs" />
|
||||
<Compile Include="Linq\IJEnumerable.cs" />
|
||||
<Compile Include="Linq\JArray.cs" />
|
||||
@@ -110,6 +109,7 @@
|
||||
<Compile Include="Linq\JObject.cs" />
|
||||
<Compile Include="Linq\JPath.cs" />
|
||||
<Compile Include="Linq\JProperty.cs" />
|
||||
<Compile Include="Linq\JPropertyDescriptor.cs" />
|
||||
<Compile Include="Linq\JRaw.cs" />
|
||||
<Compile Include="Linq\JToken.cs" />
|
||||
<Compile Include="Linq\JTokenEqualityComparer.cs" />
|
||||
|
||||
@@ -114,7 +114,7 @@
|
||||
<Compile Include="Serialization\JsonPrimitiveContract.cs" />
|
||||
<Compile Include="Serialization\DynamicValueProvider.cs" />
|
||||
<Compile Include="Serialization\ErrorEventArgs.cs" />
|
||||
<Compile Include="Linq\ComponentModel\JPropertyDescriptor.cs" />
|
||||
<Compile Include="Linq\JPropertyDescriptor.cs" />
|
||||
<Compile Include="Serialization\DefaultReferenceResolver.cs" />
|
||||
<Compile Include="PreserveReferencesHandling.cs" />
|
||||
<Compile Include="IJsonLineInfo.cs" />
|
||||
@@ -262,5 +262,6 @@
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Dynamic.snk" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
@@ -110,7 +110,7 @@ using System.Security;
|
||||
// by using the '*' as shown below:
|
||||
[assembly: AssemblyVersion("4.0.2.0")]
|
||||
#if !PocketPC
|
||||
[assembly: AssemblyFileVersion("4.0.2.13722")]
|
||||
[assembly: AssemblyFileVersion("4.0.2.13728")]
|
||||
#endif
|
||||
|
||||
[assembly: CLSCompliant(true)]
|
||||
|
||||
@@ -124,7 +124,6 @@ namespace Newtonsoft.Json.Serialization
|
||||
if (propertyInfo.IsVirtual())
|
||||
{
|
||||
Type currentType = propertyInfo.DeclaringType;
|
||||
Type[] types = propertyInfo.GetIndexParameters().Select(p => p.ParameterType).ToArray();
|
||||
|
||||
while (result == null && currentType != null)
|
||||
{
|
||||
|
||||
@@ -631,5 +631,39 @@ namespace Newtonsoft.Json.Utilities
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the index of the first occurrence in a sequence by using the default equality comparer.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource">The type of the elements of source.</typeparam>
|
||||
/// <param name="list">A sequence in which to locate a value.</param>
|
||||
/// <param name="value">The object to locate in the sequence</param>
|
||||
/// <returns>The zero-based index of the first occurrence of value within the entire sequence, if found; otherwise, –1.</returns>
|
||||
public static int IndexOf<TSource>(this IEnumerable<TSource> list, TSource value) where TSource : IEquatable<TSource>
|
||||
{
|
||||
return list.IndexOf<TSource>(value, EqualityComparer<TSource>.Default);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the index of the first occurrence in a sequence by using a specified IEqualityComparer.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource">The type of the elements of source.</typeparam>
|
||||
/// <param name="list">A sequence in which to locate a value.</param>
|
||||
/// <param name="value">The object to locate in the sequence</param>
|
||||
/// <param name="comparer">An equality comparer to compare values.</param>
|
||||
/// <returns>The zero-based index of the first occurrence of value within the entire sequence, if found; otherwise, –1.</returns>
|
||||
public static int IndexOf<TSource>(this IEnumerable<TSource> list, TSource value, IEqualityComparer<TSource> comparer)
|
||||
{
|
||||
int index = 0;
|
||||
foreach (TSource item in list)
|
||||
{
|
||||
if (comparer.Equals(item, value))
|
||||
{
|
||||
return index;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user