-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:
JamesNK
2011-05-28 00:46:38 +00:00
parent cc44f53c1a
commit b3cc3e88ac
19 changed files with 337 additions and 337 deletions
@@ -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
+7
View File
@@ -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>
+6
View File
@@ -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.
+151 -227
View File
@@ -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();
}
+66 -19
View File
@@ -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);
}
+26 -49
View File
@@ -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;
@@ -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"/>.
+9 -28
View File
@@ -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" />
+2 -1
View File
@@ -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;
}
}
}