Allow passing null to JsonArray.Add()
[mono.git] / mcs / class / System.Json / System.Json / JsonArray.cs
index 21d0d03e5ca891e8bfb2bcc9cd4af98b6d2c24c9..524e3e8b75007c0163ca85dce45f1bf4c003b4cb 100644 (file)
-// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
 
+using System;
 using System.Collections;
 using System.Collections.Generic;
-using System.Diagnostics.CodeAnalysis;
 using System.Globalization;
-using System.Runtime.Serialization;
-using System.Xml;
+using System.IO;
+using System.Text;
 
 namespace System.Json
 {
-    /// <summary>
-    /// A JsonArray is an ordered sequence of zero or more <see cref="System.Json.JsonValue"/> objects.
-    /// </summary>
-    [SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix",
-        Justification = "Array already conveys the meaning of collection")]
-    [DataContract]
-    public sealed class JsonArray : JsonValue, IList<JsonValue>
-    {
-        [DataMember]
-        private List<JsonValue> values = new List<JsonValue>();
-
-        /// <summary>
-        /// Creates an instance of the <see cref="System.Json.JsonArray"/> class initialized by
-        /// an <see cref="System.Collections.Generic.IEnumerable{T}"/> enumeration of
-        /// objects of type <see cref="System.Json.JsonValue"/>.
-        /// </summary>
-        /// <param name="items">The <see cref="System.Collections.Generic.IEnumerable{T}"/> enumeration
-        /// of objects of type <see cref="System.Json.JsonValue"/> used to initialize the JavaScript Object Notation (JSON)
-        /// array.</param>
-        /// <exception cref="System.ArgumentNullException">If items is null.</exception>
-        /// <exception cref="System.ArgumentException">If any of the items in the collection
-        /// is a <see cref="System.Json.JsonValue"/> with <see cref="System.Json.JsonValue.JsonType"/> property of
-        /// value <see cref="F:System.Json.JsonType.Default"/>.</exception>
-        public JsonArray(IEnumerable<JsonValue> items)
-        {
-            AddRange(items);
-        }
-
-        /// <summary>
-        /// Creates an instance of the <see cref="System.Json.JsonArray"/> class, initialized by an array of type <see cref="System.Json.JsonValue"/>.
-        /// </summary>
-        /// <param name="items">The array of type <see cref="System.Json.JsonValue"/> used to initialize the
-        /// JavaScript Object Notation (JSON) array.</param>
-        /// <exception cref="System.ArgumentException">If any of the items in the collection
-        /// is a <see cref="System.Json.JsonValue"/> with <see cref="System.Json.JsonValue.JsonType"/> property of
-        /// value <see cref="F:System.Json.JsonType.Default"/>.</exception>
-        public JsonArray(params JsonValue[] items)
-        {
-            if (items != null)
-            {
-                AddRange(items);
-            }
-        }
-
-        /// <summary>
-        /// Gets the JSON type of this <see cref="System.Json.JsonArray"/>. The return value
-        /// is always <see cref="F:System.Json.JsonType.Array"/>.
-        /// </summary>
-        public override JsonType JsonType
-        {
-            get { return JsonType.Array; }
-        }
-
-        /// <summary>
-        /// Gets a value indicating whether the <see cref="System.Json.JsonArray"/> is read-only.
-        /// </summary>
-        public bool IsReadOnly
-        {
-            get { return ((IList)values).IsReadOnly; }
-        }
-
-        /// <summary>
-        /// Returns the number of <see cref="System.Json.JsonValue"/> elements in the array.
-        /// </summary>
-        public override int Count
-        {
-            get { return values.Count; }
-        }
-
-        /// <summary>
-        /// Gets or sets the JSON value at a specified index.
-        /// </summary>
-        /// <param name="index">The zero-based index of the element to get or set.</param>
-        /// <returns>The <see cref="System.Json.JsonValue"/> element at the specified index.</returns>
-        /// <exception cref="System.ArgumentOutOfRangeException">If index is not a valid index for this array.</exception>
-        /// <exception cref="System.ArgumentException">The property is set and the value is a
-        /// <see cref="System.Json.JsonValue"/> with <see cref="System.Json.JsonValue.JsonType"/>
-        /// property of value <see cref="F:System.Json.JsonType.Default"/>.</exception>
-        public override JsonValue this[int index]
-        {
-            get { return values[index]; }
-
-            set
-            {
-                if (value != null && value.JsonType == JsonType.Default)
-                {
-                    throw new ArgumentNullException("value", Properties.Resources.UseOfDefaultNotAllowed);
-                }
-
-                JsonValue oldValue = values[index];
-                RaiseItemChanging(value, JsonValueChange.Replace, index);
-                values[index] = value;
-                RaiseItemChanged(oldValue, JsonValueChange.Replace, index);
-            }
-        }
-
-        /// <summary>
-        /// Adds the elements from a collection of type <see cref="System.Json.JsonValue"/> to this instance.
-        /// </summary>
-        /// <param name="items">Collection of items to add.</param>
-        /// <exception cref="System.ArgumentNullException">If items is null.</exception>
-        /// <exception cref="System.ArgumentException">If any of the items in the collection
-        /// is a <see cref="System.Json.JsonValue"/> with <see cref="System.Json.JsonValue.JsonType"/> property of
-        /// value <see cref="F:System.Json.JsonType.Default"/>.</exception>
-        public void AddRange(IEnumerable<JsonValue> items)
-        {
-            if (items == null)
-            {
-                throw new ArgumentNullException("items");
-            }
-
-            if (ChangingListenersCount > 0)
-            {
-                int index = Count;
-                foreach (JsonValue toBeAdded in items)
-                {
-                    RaiseItemChanging(toBeAdded, JsonValueChange.Add, index++);
-                }
-            }
-
-            foreach (JsonValue item in items)
-            {
-                if (item != null && item.JsonType == JsonType.Default)
-                {
-                    throw new ArgumentNullException("items", Properties.Resources.UseOfDefaultNotAllowed);
-                }
-
-                values.Add(item);
-                RaiseItemChanged(item, JsonValueChange.Add, values.Count - 1);
-            }
-        }
-
-        /// <summary>
-        /// Adds the elements from an array of type <see cref="System.Json.JsonValue"/> to this instance.
-        /// </summary>
-        /// <param name="items">The array of type JsonValue to be added to this instance.</param>
-        /// <exception cref="System.ArgumentNullException">If items is null.</exception>
-        /// <exception cref="System.ArgumentException">If any of the items in the array
-        /// is a <see cref="System.Json.JsonValue"/> with <see cref="System.Json.JsonValue.JsonType"/> property of
-        /// value <see cref="F:System.Json.JsonType.Default"/>.</exception>
-        public void AddRange(params JsonValue[] items)
-        {
-            AddRange(items as IEnumerable<JsonValue>);
-        }
-
-        /// <summary>
-        /// Searches for a specified object and returns the zero-based index of its first
-        /// occurrence within this <see cref="System.Json.JsonArray"/>.
-        /// </summary>
-        /// <param name="item">The <see cref="System.Json.JsonValue"/> object to look up.</param>
-        /// <returns>The zero-based index of the first occurrence of item within the
-        /// <see cref="System.Json.JsonArray"/>, if found; otherwise, -1.</returns>
-        public int IndexOf(JsonValue item)
-        {
-            return values.IndexOf(item);
-        }
-
-        /// <summary>
-        /// Insert a JSON CLR type into the array at a specified index.
-        /// </summary>
-        /// <param name="index">The zero-based index at which the item should be inserted.</param>
-        /// <param name="item">The <see cref="System.Json.JsonValue"/> object to insert.</param>
-        /// <exception cref="System.ArgumentOutOfRangeException">If index is less than zero or larger than
-        /// the size of the array.</exception>
-        /// <exception cref="System.ArgumentException">If the object to insert has a
-        /// <see cref="System.Json.JsonValue.JsonType"/> property of value
-        /// <see cref="F:System.Json.JsonType.Default"/>.</exception>
-        public void Insert(int index, JsonValue item)
-        {
-            if (item != null && item.JsonType == JsonType.Default)
-            {
-                throw new ArgumentNullException("item", Properties.Resources.UseOfDefaultNotAllowed);
-            }
-
-            RaiseItemChanging(item, JsonValueChange.Add, index);
-            values.Insert(index, item);
-            RaiseItemChanged(item, JsonValueChange.Add, index);
-        }
-
-        /// <summary>
-        /// Remove the JSON value at a specified index of <see cref="System.Json.JsonArray"/>.
-        /// </summary>
-        /// <param name="index">The zero-based index at which to remove the <see cref="System.Json.JsonValue"/>.</param>
-        /// <exception cref="System.ArgumentOutOfRangeException">If index is less than zero or index
-        /// is equal or larger than the size of the array.</exception>
-        public void RemoveAt(int index)
-        {
-            JsonValue item = values[index];
-            RaiseItemChanging(item, JsonValueChange.Remove, index);
-            values.RemoveAt(index);
-            RaiseItemChanged(item, JsonValueChange.Remove, index);
-        }
-
-        /// <summary>
-        /// Adds a <see cref="System.Json.JsonValue"/> object to the end of the array.
-        /// </summary>
-        /// <param name="item">The <see cref="System.Json.JsonValue"/> object to add.</param>
-        /// <exception cref="System.ArgumentException">If the object to add has a
-        /// <see cref="System.Json.JsonValue.JsonType"/> property of value
-        /// <see cref="F:System.Json.JsonType.Default"/>.</exception>
-        public void Add(JsonValue item)
-        {
-            if (item != null && item.JsonType == JsonType.Default)
-            {
-                throw new ArgumentNullException("item", Properties.Resources.UseOfDefaultNotAllowed);
-            }
-
-            int index = Count;
-            RaiseItemChanging(item, JsonValueChange.Add, index);
-            values.Add(item);
-            RaiseItemChanged(item, JsonValueChange.Add, index);
-        }
-
-        /// <summary>
-        /// Removes all JSON CLR types from the <see cref="System.Json.JsonArray"/>.
-        /// </summary>
-        public void Clear()
-        {
-            RaiseItemChanging(null, JsonValueChange.Clear, 0);
-            values.Clear();
-            RaiseItemChanged(null, JsonValueChange.Clear, 0);
-        }
-
-        /// <summary>
-        /// Checks whether a specified JSON CLR type is in the <see cref="System.Json.JsonArray"/>.
-        /// </summary>
-        /// <param name="item">The <see cref="System.Json.JsonValue"/> to check for in the array.</param>
-        /// <returns>true if item is found in the <see cref="System.Json.JsonArray"/>; otherwise, false.</returns>
-        public bool Contains(JsonValue item)
-        {
-            return values.Contains(item);
-        }
-
-        /// <summary>
-        /// Copies the contents of the current JSON CLR array instance into a specified
-        /// destination array beginning at the specified index.
-        /// </summary>
-        /// <param name="array">The destination array to which the elements of the current
-        /// <see cref="System.Json.JsonArray"/> object are copied.</param>
-        /// <param name="arrayIndex">The zero-based index in the destination array at which the
-        /// copying of the elements of the JSON CLR array begins.</param>
-        public void CopyTo(JsonValue[] array, int arrayIndex)
-        {
-            values.CopyTo(array, arrayIndex);
-        }
-
-        /// <summary>
-        /// Removes the first occurrence of the specified JSON value from the array.
-        /// </summary>
-        /// <param name="item">The <see cref="System.Json.JsonValue"/> to remove from the <see cref="System.Json.JsonArray"/>.</param>
-        /// <returns>true if item is successfully removed; otherwise, false. This method
-        /// also returns false if item was not found in the <see cref="System.Json.JsonArray"/>.</returns>
-        public bool Remove(JsonValue item)
-        {
-            int index = -1;
-            if (ChangingListenersCount > 0 || ChangedListenersCount > 0)
-            {
-                index = IndexOf(item);
-            }
-
-            if (index >= 0)
-            {
-                RaiseItemChanging(item, JsonValueChange.Remove, index);
-            }
-
-            bool result = values.Remove(item);
-            if (index >= 0)
-            {
-                RaiseItemChanged(item, JsonValueChange.Remove, index);
-            }
-
-            return result;
-        }
-
-        /// <summary>
-        /// Returns an enumerator that iterates through the <see cref="System.Json.JsonValue"/> objects in the array.
-        /// </summary>
-        /// <returns>Returns an <see cref="System.Collections.IEnumerator"/> object that
-        /// iterates through the <see cref="System.Json.JsonValue"/> elements in this <see cref="System.Json.JsonArray"/>.</returns>
-        IEnumerator IEnumerable.GetEnumerator()
-        {
-            return values.GetEnumerator();
-        }
-
-        /// <summary>
-        /// Safe indexer for the <see cref="System.Json.JsonValue"/> type. 
-        /// </summary>
-        /// <param name="index">The zero-based index of the element to get.</param>
-        /// <returns>If the index is within the array bounds and the value corresponding to the
-        /// index is not null, then it will return that value. Otherwise it will return a
-        /// <see cref="System.Json.JsonValue"/> instance with <see cref="System.Json.JsonValue.JsonType"/>
-        /// equals to <see cref="F:System.Json.JsonType.Default"/>.</returns>
-        public override JsonValue ValueOrDefault(int index)
-        {
-            if (index >= 0 && index < Count && this[index] != null)
-            {
-                return this[index];
-            }
-
-            return base.ValueOrDefault(index);
-        }
-
-        /// <summary>
-        /// Returns an enumerator that iterates through the <see cref="System.Json.JsonValue"/> objects in the array.
-        /// </summary>
-        /// <returns>Returns an <see cref="System.Collections.Generic.IEnumerator{T}"/> object that
-        /// iterates through the <see cref="System.Json.JsonValue"/> elements in this <see cref="System.Json.JsonArray"/>.</returns>
-        public new IEnumerator<JsonValue> GetEnumerator()
-        {
-            return values.GetEnumerator();
-        }
-
-        /// <summary>
-        /// Returns an enumerator which iterates through the values in this object.
-        /// </summary>
-        /// <returns>An <see cref="System.Collections.Generic.IEnumerator{T}"/> which iterates through the values in this object.</returns>
-        /// <remarks>The enumerator returned by this class contains one pair for each element
-        /// in this array, whose key is the element index (as a string), and the value is the
-        /// element itself.</remarks>
-        protected override IEnumerator<KeyValuePair<string, JsonValue>> GetKeyValuePairEnumerator()
-        {
-            for (int i = 0; i < values.Count; i++)
-            {
-                yield return new KeyValuePair<string, JsonValue>(i.ToString(CultureInfo.InvariantCulture), values[i]);
-            }
-        }
-
-        /// <summary>
-        /// Callback method called to let an instance write the proper JXML attribute when saving this
-        /// instance.
-        /// </summary>
-        /// <param name="jsonWriter">The JXML writer used to write JSON.</param>
-        internal override void WriteAttributeString(XmlDictionaryWriter jsonWriter)
-        {
-            if (jsonWriter == null)
-            {
-                throw new ArgumentNullException("jsonWriter");
-            }
-
-            jsonWriter.WriteAttributeString(JXmlToJsonValueConverter.TypeAttributeName, JXmlToJsonValueConverter.ArrayAttributeValue);
-        }
-
-        /// <summary>
-        /// Callback method called during Save operations to let the instance write the start element
-        /// and return the next element in the collection.
-        /// </summary>
-        /// <param name="jsonWriter">The JXML writer used to write JSON.</param>
-        /// <param name="currentIndex">The index within this collection.</param>
-        /// <returns>The next item in the collection, or null of there are no more items.</returns>
-        internal override JsonValue WriteStartElementAndGetNext(XmlDictionaryWriter jsonWriter, int currentIndex)
-        {
-            if (jsonWriter == null)
-            {
-                throw new ArgumentNullException("jsonWriter");
-            }
-
-            jsonWriter.WriteStartElement(JXmlToJsonValueConverter.ItemElementName);
-            JsonValue nextValue = this[currentIndex];
-            return nextValue;
-        }
-
-        private void RaiseItemChanging(JsonValue child, JsonValueChange change, int index)
-        {
-            if (ChangingListenersCount > 0)
-            {
-                RaiseChangingEvent(this, new JsonValueChangeEventArgs(child, change, index));
-            }
-        }
-
-        private void RaiseItemChanged(JsonValue child, JsonValueChange change, int index)
-        {
-            if (ChangedListenersCount > 0)
-            {
-                RaiseChangedEvent(this, new JsonValueChangeEventArgs(child, change, index));
-            }
-        }
-    }
+       public class JsonArray : JsonValue, IList<JsonValue>
+       {
+               List<JsonValue> list;
+
+               public JsonArray (params JsonValue [] items)
+               {
+                       list = new List<JsonValue> ();
+                       AddRange (items);
+               }
+
+               public JsonArray (IEnumerable<JsonValue> items)
+               {
+                       if (items == null)
+                               throw new ArgumentNullException ("items");
+
+                       list = new List<JsonValue> (items);
+               }
+
+               public override int Count {
+                       get { return list.Count; }
+               }
+
+               public bool IsReadOnly {
+                       get { return false; }
+               }
+
+               public override sealed JsonValue this [int index] {
+                       get { return list [index]; }
+                       set { list [index] = value; }
+               }
+
+               public override JsonType JsonType {
+                       get { return JsonType.Array; }
+               }
+
+               public void Add (JsonValue item)
+               {
+                       list.Add (item);
+               }
+
+               public void AddRange (IEnumerable<JsonValue> items)
+               {
+                       if (items == null)
+                               throw new ArgumentNullException ("items");
+
+                       list.AddRange (items);
+               }
+
+               public void AddRange (params JsonValue [] items)
+               {
+                       if (items == null)
+                               return;
+
+                       list.AddRange (items);
+               }
+
+               public void Clear ()
+               {
+                       list.Clear ();
+               }
+
+               public bool Contains (JsonValue item)
+               {
+                       return list.Contains (item);
+               }
+
+               public void CopyTo (JsonValue [] array, int arrayIndex)
+               {
+                       list.CopyTo (array, arrayIndex);
+               }
+
+               public int IndexOf (JsonValue item)
+               {
+                       return list.IndexOf (item);
+               }
+
+               public void Insert (int index, JsonValue item)
+               {
+                       list.Insert (index, item);
+               }
+
+               public bool Remove (JsonValue item)
+               {
+                       return list.Remove (item);
+               }
+
+               public void RemoveAt (int index)
+               {
+                       list.RemoveAt (index);
+               }
+
+               public override void Save (Stream stream)
+               {
+                       if (stream == null)
+                               throw new ArgumentNullException ("stream");
+                       stream.WriteByte ((byte) '[');
+                       for (int i = 0; i < list.Count; i++) {
+                               JsonValue v = list [i];
+                               if (v != null)
+                                       v.Save (stream);
+                               else {
+                                       stream.WriteByte ((byte) 'n');
+                                       stream.WriteByte ((byte) 'u');
+                                       stream.WriteByte ((byte) 'l');
+                                       stream.WriteByte ((byte) 'l');
+                               }
+
+                               if (i < Count - 1) {
+                                       stream.WriteByte ((byte) ',');
+                                       stream.WriteByte ((byte) ' ');
+                               }
+                       }
+                       stream.WriteByte ((byte) ']');
+               }
+
+               IEnumerator<JsonValue> IEnumerable<JsonValue>.GetEnumerator ()
+               {
+                       return list.GetEnumerator ();
+               }
+
+               IEnumerator IEnumerable.GetEnumerator ()
+               {
+                       return list.GetEnumerator ();
+               }
+       }
 }