Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarek Safar <marek.safar@gmail.com>2012-12-05 15:11:16 +0400
committerMarek Safar <marek.safar@gmail.com>2012-12-05 15:11:16 +0400
commitf79fec62c57dc3d59807f06ac14c02690bb942f1 (patch)
tree493b6fe07a9faa27985d9b04d21b96f65e809f28 /mcs/class/System.Json.Microsoft
parentc4b3a047f1c452fede8bf6b7a2d4d3a80399b9af (diff)
Bring back 2.10 based System.Json and move aspnet stack version to System.Json.Microsoft
Diffstat (limited to 'mcs/class/System.Json.Microsoft')
-rwxr-xr-xmcs/class/System.Json.Microsoft/Assembly/AssemblyInfo.cs42
-rwxr-xr-xmcs/class/System.Json.Microsoft/Assembly/ChangeLog16
-rw-r--r--mcs/class/System.Json.Microsoft/ChangeLog29
-rw-r--r--mcs/class/System.Json.Microsoft/Makefile30
-rw-r--r--mcs/class/System.Json.Microsoft/System.Json.Microsoft.dll.sources22
-rw-r--r--mcs/class/System.Json.Microsoft/System.Json.Microsoft_test.dll.sources1
-rw-r--r--mcs/class/System.Json.Microsoft/System.Json/Extensions/JsonValueExtensions.cs383
-rw-r--r--mcs/class/System.Json.Microsoft/System.Json/GlobalSuppressions.cs6
-rw-r--r--mcs/class/System.Json.Microsoft/System.Json/JXmlToJsonValueConverter.cs304
-rw-r--r--mcs/class/System.Json.Microsoft/System.Json/JsonArray.cs389
-rw-r--r--mcs/class/System.Json.Microsoft/System.Json/JsonObject.cs474
-rw-r--r--mcs/class/System.Json.Microsoft/System.Json/JsonPrimitive.cs1151
-rw-r--r--mcs/class/System.Json.Microsoft/System.Json/JsonType.cs50
-rw-r--r--mcs/class/System.Json.Microsoft/System.Json/JsonValue.cs1249
-rw-r--r--mcs/class/System.Json.Microsoft/System.Json/JsonValueChange.cs30
-rw-r--r--mcs/class/System.Json.Microsoft/System.Json/JsonValueChangeEventArgs.cs98
-rw-r--r--mcs/class/System.Json.Microsoft/System.Json/JsonValueDynamicMetaObject.cs384
-rw-r--r--mcs/class/System.Json.Microsoft/System.Json/JsonValueLinqExtensions.cs37
-rw-r--r--mcs/class/System.Json.Microsoft/System.Json/NGenWrapper.cs48
-rw-r--r--mcs/class/System.Json.Microsoft/System.Json/Properties/AssemblyInfo.cs12
-rw-r--r--mcs/class/System.Json.Microsoft/System.Json/Properties/Resources.Designer.cs216
-rw-r--r--mcs/class/System.Json.Microsoft/System.Json/Properties/Resources.resx171
-rw-r--r--mcs/class/System.Json.Microsoft/Test/System.Json/JsonValueTest.cs30
23 files changed, 5172 insertions, 0 deletions
diff --git a/mcs/class/System.Json.Microsoft/Assembly/AssemblyInfo.cs b/mcs/class/System.Json.Microsoft/Assembly/AssemblyInfo.cs
new file mode 100755
index 00000000000..702394f1832
--- /dev/null
+++ b/mcs/class/System.Json.Microsoft/Assembly/AssemblyInfo.cs
@@ -0,0 +1,42 @@
+//
+// AssemblyInfo.cs
+//
+// Authors:
+// Marek Safar (marek.safar@gmail.com)
+//
+// Copyright (C) 2007 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Reflection;
+using System.Resources;
+using System.Security;
+using System.Security.Permissions;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about the System.Json assembly
+
+[assembly: AssemblyDefaultAlias ("System.Json.Microsoft.dll")]
+
+[assembly: AssemblyInformationalVersion (Consts.FxFileVersion)]
diff --git a/mcs/class/System.Json.Microsoft/Assembly/ChangeLog b/mcs/class/System.Json.Microsoft/Assembly/ChangeLog
new file mode 100755
index 00000000000..1fcfb76e98c
--- /dev/null
+++ b/mcs/class/System.Json.Microsoft/Assembly/ChangeLog
@@ -0,0 +1,16 @@
+2010-03-10 Atsushi Enomoto <atsushi@ximian.com>
+
+ * AssemblyInfo.cs : use the same pub key in 2.0 (dummy), to ease
+ testing locally.
+
+2008-05-07 Sebastien Pouliot <sebastien@ximian.com>
+
+ * AssemblyInfo.cs: Remove AssemblyDelaySign(true) since it's
+ not always needed and can be controlled from the Makefile.
+ Adjust public key for System.Windows (InternalsVisibleTo)
+
+2008-04-13 Jb Evain <jbevain@novell.com>
+
+ * AssemblyInfo.cs: agmono is renamed to Mono.Moonlight.
+ Merged from the Moonlight 2 branch.
+
diff --git a/mcs/class/System.Json.Microsoft/ChangeLog b/mcs/class/System.Json.Microsoft/ChangeLog
new file mode 100644
index 00000000000..3782149ab0f
--- /dev/null
+++ b/mcs/class/System.Json.Microsoft/ChangeLog
@@ -0,0 +1,29 @@
+2010-04-01 Miguel de Icaza <miguel@novell.com>
+
+ * JsonValue.cs: We need to use Convert.ToXXXX for numbers as we
+ always end up reporting the value JsonType.Number regardless of
+ the underlying storage (int, long or decimal). The parser
+ picks the best storage suitable for the data, and can end up using
+ "ints" for values that sometimes use longs.
+
+ This causes problems when derefercing the data for example, if you
+ have an int and try to get it out as a long you end up with an
+ invalid cast exception.
+
+2010-03-10 Atsushi Enomoto <atsushi@ximian.com>
+
+ * System.Json.dll.sources : remove JsonReader.cs.
+
+2010-03-10 Atsushi Enomoto <atsushi@ximian.com>
+
+ * Makefile : reference System.Xml and System.ServiceModel.Web (for
+ moonlight compatibility).
+
+2009-08-13 Atsushi Enomoto <atsushi@ximian.com>
+
+ * Makefile : update profile check.
+
+2008-06-10 Atsushi Enomoto <atsushi@ximian.com>
+
+ * System.Json.dll.sources, Makefile : initial checkin.
+
diff --git a/mcs/class/System.Json.Microsoft/Makefile b/mcs/class/System.Json.Microsoft/Makefile
new file mode 100644
index 00000000000..5124d3f6e6c
--- /dev/null
+++ b/mcs/class/System.Json.Microsoft/Makefile
@@ -0,0 +1,30 @@
+thisdir = class/System.Json.Microsoft
+SUBDIRS =
+include ../../build/rules.make
+
+System.Json.Properties.Resources.resources: System.Json/Properties/Resources.resx
+ $(RESGEN) "$<" "$@"
+
+LIBRARY = System.Json.Microsoft.dll
+LIB_MCS_FLAGS = /d:ASPNETMVC -keyfile:../winfx.pub -delaysign \
+ /r:System.dll \
+ /r:System.Xml.dll \
+ /r:System.Core.dll \
+ /r:System.Runtime.Serialization.dll \
+ /resource:System.Json.Properties.Resources.resources
+
+EXTRA_DISTFILES = System.Json/Properties/Resources.resx
+
+ifeq (4, $(FRAMEWORK_VERSION_MAJOR))
+LIB_MCS_FLAGS += /r:Microsoft.CSharp.dll -d:FEATURE_DYNAMIC
+endif
+
+ifeq (monodroid, $(PROFILE))
+LIB_MCS_FLAGS += -d:FEATURE_DYNAMIC
+endif
+
+TEST_MCS_FLAGS = $(LIB_MCS_FLAGS)
+
+include ../../build/library.make
+
+$(the_lib): System.Json.Properties.Resources.resources
diff --git a/mcs/class/System.Json.Microsoft/System.Json.Microsoft.dll.sources b/mcs/class/System.Json.Microsoft/System.Json.Microsoft.dll.sources
new file mode 100644
index 00000000000..4d2f589c7ab
--- /dev/null
+++ b/mcs/class/System.Json.Microsoft/System.Json.Microsoft.dll.sources
@@ -0,0 +1,22 @@
+../../build/common/Consts.cs
+Assembly/AssemblyInfo.cs
+
+../../../external/aspnetwebstack/src/RS.cs
+../../../external/aspnetwebstack/src/CommonAssemblyInfo.cs
+../../../external/aspnetwebstack/src/TransparentCommonAssemblyInfo.cs
+
+System.Json/Properties/AssemblyInfo.cs
+System.Json/Extensions/JsonValueExtensions.cs
+System.Json/GlobalSuppressions.cs
+System.Json/JXmlToJsonValueConverter.cs
+System.Json/JsonArray.cs
+System.Json/JsonObject.cs
+System.Json/JsonPrimitive.cs
+System.Json/JsonType.cs
+System.Json/JsonValue.cs
+System.Json/JsonValueChange.cs
+System.Json/JsonValueChangeEventArgs.cs
+System.Json/JsonValueDynamicMetaObject.cs
+System.Json/JsonValueLinqExtensions.cs
+System.Json/NGenWrapper.cs
+System.Json/Properties/Resources.Designer.cs
diff --git a/mcs/class/System.Json.Microsoft/System.Json.Microsoft_test.dll.sources b/mcs/class/System.Json.Microsoft/System.Json.Microsoft_test.dll.sources
new file mode 100644
index 00000000000..8d6ae225c73
--- /dev/null
+++ b/mcs/class/System.Json.Microsoft/System.Json.Microsoft_test.dll.sources
@@ -0,0 +1 @@
+System.Json/JsonValueTest.cs \ No newline at end of file
diff --git a/mcs/class/System.Json.Microsoft/System.Json/Extensions/JsonValueExtensions.cs b/mcs/class/System.Json.Microsoft/System.Json/Extensions/JsonValueExtensions.cs
new file mode 100644
index 00000000000..2ea0c14bbc1
--- /dev/null
+++ b/mcs/class/System.Json.Microsoft/System.Json/Extensions/JsonValueExtensions.cs
@@ -0,0 +1,383 @@
+// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
+#if FEATURE_DYNAMIC
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Diagnostics.CodeAnalysis;
+using System.Dynamic;
+using System.IO;
+using System.Json;
+using System.Linq.Expressions;
+
+namespace System.Runtime.Serialization.Json
+{
+ /// <summary>
+ /// This class extends the functionality of the <see cref="JsonValue"/> type.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static class JsonValueExtensions
+ {
+ /// <summary>
+ /// Creates a <see cref="System.Json.JsonValue"/> object based on an arbitrary CLR object.
+ /// </summary>
+ /// <param name="value">The object to be converted to <see cref="System.Json.JsonValue"/>.</param>
+ /// <returns>The <see cref="System.Json.JsonValue"/> which represents the given object.</returns>
+ /// <remarks>The conversion is done through the <see cref="System.Runtime.Serialization.Json.DataContractJsonSerializer"/>;
+ /// the object is first serialized into JSON using the serializer, then parsed into a <see cref="System.Json.JsonValue"/>
+ /// object.</remarks>
+ public static JsonValue CreateFrom(object value)
+ {
+ JsonValue jsonValue = null;
+
+ if (value != null)
+ {
+ jsonValue = value as JsonValue;
+
+ if (jsonValue == null)
+ {
+ jsonValue = JsonValueExtensions.CreatePrimitive(value);
+
+ if (jsonValue == null)
+ {
+ jsonValue = JsonValueExtensions.CreateFromDynamic(value);
+
+ if (jsonValue == null)
+ {
+ jsonValue = JsonValueExtensions.CreateFromComplex(value);
+ }
+ }
+ }
+ }
+
+ return jsonValue;
+ }
+
+ /// <summary>
+ /// Attempts to convert this <see cref="System.Json.JsonValue"/> instance into the type T.
+ /// </summary>
+ /// <typeparam name="T">The type to which the conversion is being performed.</typeparam>
+ /// <param name="jsonValue">The <see cref="JsonValue"/> instance this method extension is to be applied to.</param>
+ /// <param name="valueOfT">An instance of T initialized with this instance, or the default
+ /// value of T, if the conversion cannot be performed.</param>
+ /// <returns>true if this <see cref="System.Json.JsonValue"/> instance can be read as type T; otherwise, false.</returns>
+ public static bool TryReadAsType<T>(this JsonValue jsonValue, out T valueOfT)
+ {
+ if (jsonValue == null)
+ {
+ throw new ArgumentNullException("jsonValue");
+ }
+
+ object value;
+ if (JsonValueExtensions.TryReadAsType(jsonValue, typeof(T), out value))
+ {
+ valueOfT = (T)value;
+ return true;
+ }
+
+ valueOfT = default(T);
+ return false;
+ }
+
+ /// <summary>
+ /// Attempts to convert this <see cref="System.Json.JsonValue"/> instance into the type T.
+ /// </summary>
+ /// <typeparam name="T">The type to which the conversion is being performed.</typeparam>
+ /// <param name="jsonValue">The <see cref="JsonValue"/> instance this method extension is to be applied to.</param>
+ /// <returns>An instance of T initialized with the <see cref="System.Json.JsonValue"/> value
+ /// specified if the conversion.</returns>
+ /// <exception cref="System.NotSupportedException">If this <see cref="System.Json.JsonValue"/> value cannot be
+ /// converted into the type T.</exception>
+ [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter",
+ Justification = "The generic parameter is used to specify the output type")]
+ public static T ReadAsType<T>(this JsonValue jsonValue)
+ {
+ if (jsonValue == null)
+ {
+ throw new ArgumentNullException("jsonValue");
+ }
+
+ return (T)JsonValueExtensions.ReadAsType(jsonValue, typeof(T));
+ }
+
+ /// <summary>
+ /// Attempts to convert this <see cref="System.Json.JsonValue"/> instance into the type T, returning a fallback value
+ /// if the conversion fails.
+ /// </summary>
+ /// <typeparam name="T">The type to which the conversion is being performed.</typeparam>
+ /// <param name="jsonValue">The <see cref="JsonValue"/> instance this method extension is to be applied to.</param>
+ /// <param name="fallback">A fallback value to be retuned in case the conversion cannot be performed.</param>
+ /// <returns>An instance of T initialized with the <see cref="System.Json.JsonValue"/> value
+ /// specified if the conversion succeeds or the specified fallback value if it fails.</returns>
+ public static T ReadAsType<T>(this JsonValue jsonValue, T fallback)
+ {
+ if (jsonValue == null)
+ {
+ throw new ArgumentNullException("jsonValue");
+ }
+
+ T outVal;
+ if (JsonValueExtensions.TryReadAsType<T>(jsonValue, out outVal))
+ {
+ return outVal;
+ }
+
+ return fallback;
+ }
+
+ /// <summary>
+ /// Attempts to convert this <see cref="System.Json.JsonValue"/> instance into an instance of the specified type.
+ /// </summary>
+ /// <param name="jsonValue">The <see cref="JsonValue"/> instance this method extension is to be applied to.</param>
+ /// <param name="type">The type to which the conversion is being performed.</param>
+ /// <returns>An object instance initialized with the <see cref="System.Json.JsonValue"/> value
+ /// specified if the conversion.</returns>
+ /// <exception cref="System.NotSupportedException">If this <see cref="System.Json.JsonValue"/> value cannot be
+ /// converted into the type T.</exception>
+ public static object ReadAsType(this JsonValue jsonValue, Type type)
+ {
+ if (jsonValue == null)
+ {
+ throw new ArgumentNullException("jsonValue");
+ }
+
+ if (type == null)
+ {
+ throw new ArgumentNullException("type");
+ }
+
+ object result;
+ if (JsonValueExtensions.TryReadAsType(jsonValue, type, out result))
+ {
+ return result;
+ }
+
+ throw new NotSupportedException(RS.Format(System.Json.Properties.Resources.CannotReadAsType, jsonValue.GetType().FullName, type.FullName));
+ }
+
+ /// <summary>
+ /// Attempts to convert this <see cref="System.Json.JsonValue"/> instance into an instance of the specified type.
+ /// </summary>
+ /// <param name="jsonValue">The <see cref="JsonValue"/> instance this method extension is to be applied to.</param>
+ /// <param name="type">The type to which the conversion is being performed.</param>
+ /// <param name="value">An object to be initialized with this instance or null if the conversion cannot be performed.</param>
+ /// <returns>true if this <see cref="System.Json.JsonValue"/> instance can be read as the specified type; otherwise, false.</returns>
+ [SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate",
+ Justification = "This is the non-generic version of the method.")]
+ [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exception translates to fail.")]
+ public static bool TryReadAsType(this JsonValue jsonValue, Type type, out object value)
+ {
+ if (jsonValue == null)
+ {
+ throw new ArgumentNullException("jsonValue");
+ }
+
+ if (type == null)
+ {
+ throw new ArgumentNullException("type");
+ }
+
+ if (type == typeof(JsonValue) || type == typeof(object))
+ {
+ value = jsonValue;
+ return true;
+ }
+
+ if (type == typeof(object[]) || type == typeof(Dictionary<string, object>))
+ {
+ if (!JsonValueExtensions.CanConvertToClrCollection(jsonValue, type))
+ {
+ value = null;
+ return false;
+ }
+ }
+
+ if (jsonValue.TryReadAs(type, out value))
+ {
+ return true;
+ }
+
+ try
+ {
+ using (MemoryStream ms = new MemoryStream())
+ {
+ jsonValue.Save(ms);
+ ms.Position = 0;
+ DataContractJsonSerializer dcjs = new DataContractJsonSerializer(type);
+ value = dcjs.ReadObject(ms);
+ }
+
+ return true;
+ }
+ catch (Exception)
+ {
+ value = null;
+ return false;
+ }
+ }
+
+ /// <summary>
+ /// Determines whether the specified <see cref="JsonValue"/> instance can be converted to the specified collection <see cref="Type"/>.
+ /// </summary>
+ /// <param name="jsonValue">The instance to be converted.</param>
+ /// <param name="collectionType">The collection type to convert the instance to.</param>
+ /// <returns>true if the instance can be converted, false otherwise</returns>
+ private static bool CanConvertToClrCollection(JsonValue jsonValue, Type collectionType)
+ {
+ if (jsonValue != null)
+ {
+ return (jsonValue.JsonType == JsonType.Object && collectionType == typeof(Dictionary<string, object>)) ||
+ (jsonValue.JsonType == JsonType.Array && collectionType == typeof(object[]));
+ }
+
+ return false;
+ }
+
+ private static JsonValue CreatePrimitive(object value)
+ {
+ JsonPrimitive jsonPrimitive;
+
+ if (JsonPrimitive.TryCreate(value, out jsonPrimitive))
+ {
+ return jsonPrimitive;
+ }
+
+ return null;
+ }
+
+ private static JsonValue CreateFromComplex(object value)
+ {
+ DataContractJsonSerializer dcjs = new DataContractJsonSerializer(value.GetType());
+ using (MemoryStream ms = new MemoryStream())
+ {
+ dcjs.WriteObject(ms, value);
+ ms.Position = 0;
+ return JsonValue.Load(ms);
+ }
+ }
+
+ [SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily", Justification = "value is not the same")]
+ private static JsonValue CreateFromDynamic(object value)
+ {
+ JsonObject parent = null;
+ DynamicObject dynObj = value as DynamicObject;
+
+ if (dynObj != null)
+ {
+ parent = new JsonObject();
+ Stack<CreateFromTypeStackInfo> infoStack = new Stack<CreateFromTypeStackInfo>();
+ IEnumerator<string> keys = null;
+
+ do
+ {
+ if (keys == null)
+ {
+ keys = dynObj.GetDynamicMemberNames().GetEnumerator();
+ }
+
+ while (keys.MoveNext())
+ {
+ JsonValue child = null;
+ string key = keys.Current;
+ SimpleGetMemberBinder binder = new SimpleGetMemberBinder(key);
+
+ if (dynObj.TryGetMember(binder, out value))
+ {
+ DynamicObject childDynObj = value as DynamicObject;
+
+ if (childDynObj != null)
+ {
+ child = new JsonObject();
+ parent.Add(key, child);
+
+ infoStack.Push(new CreateFromTypeStackInfo(parent, dynObj, keys));
+
+ parent = child as JsonObject;
+ dynObj = childDynObj;
+ keys = null;
+
+ break;
+ }
+ else
+ {
+ if (value != null)
+ {
+ child = value as JsonValue;
+
+ if (child == null)
+ {
+ child = JsonValueExtensions.CreatePrimitive(value);
+
+ if (child == null)
+ {
+ child = JsonValueExtensions.CreateFromComplex(value);
+ }
+ }
+ }
+
+ parent.Add(key, child);
+ }
+ }
+ }
+
+ if (infoStack.Count > 0 && keys != null)
+ {
+ CreateFromTypeStackInfo info = infoStack.Pop();
+
+ parent = info.JsonObject;
+ dynObj = info.DynamicObject;
+ keys = info.Keys;
+ }
+ }
+ while (infoStack.Count > 0);
+ }
+
+ return parent;
+ }
+
+ private class CreateFromTypeStackInfo
+ {
+ public CreateFromTypeStackInfo(JsonObject jsonObject, DynamicObject dynamicObject, IEnumerator<string> keyEnumerator)
+ {
+ JsonObject = jsonObject;
+ DynamicObject = dynamicObject;
+ Keys = keyEnumerator;
+ }
+
+ /// <summary>
+ /// Gets of sets
+ /// </summary>
+ public JsonObject JsonObject { get; set; }
+
+ /// <summary>
+ /// Gets of sets
+ /// </summary>
+ public DynamicObject DynamicObject { get; set; }
+
+ /// <summary>
+ /// Gets of sets
+ /// </summary>
+ public IEnumerator<string> Keys { get; set; }
+ }
+
+ private class SimpleGetMemberBinder : GetMemberBinder
+ {
+ public SimpleGetMemberBinder(string name)
+ : base(name, false)
+ {
+ }
+
+ public override DynamicMetaObject FallbackGetMember(DynamicMetaObject target, DynamicMetaObject errorSuggestion)
+ {
+ if (target != null && errorSuggestion == null)
+ {
+ string exceptionMessage = RS.Format(System.Json.Properties.Resources.DynamicPropertyNotDefined, target.LimitType, Name);
+ Expression throwExpression = Expression.Throw(Expression.Constant(new InvalidOperationException(exceptionMessage)), typeof(object));
+
+ errorSuggestion = new DynamicMetaObject(throwExpression, target.Restrictions);
+ }
+
+ return errorSuggestion;
+ }
+ }
+ }
+}
+#endif
diff --git a/mcs/class/System.Json.Microsoft/System.Json/GlobalSuppressions.cs b/mcs/class/System.Json.Microsoft/System.Json/GlobalSuppressions.cs
new file mode 100644
index 00000000000..5d3e5578676
--- /dev/null
+++ b/mcs/class/System.Json.Microsoft/System.Json/GlobalSuppressions.cs
@@ -0,0 +1,6 @@
+// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
+
+using System.Diagnostics.CodeAnalysis;
+
+[assembly: SuppressMessage("Microsoft.Design", "CA2210:AssembliesShouldHaveValidStrongNames", Justification = "These assemblies are delay-signed.")]
+[assembly: SuppressMessage("Microsoft.Design", "CA1020:AvoidNamespacesWithFewTypes", Justification = "Classes are grouped logically for user clarity.", Scope = "namespace", Target = "System.Runtime.Serialization.Json")]
diff --git a/mcs/class/System.Json.Microsoft/System.Json/JXmlToJsonValueConverter.cs b/mcs/class/System.Json.Microsoft/System.Json/JXmlToJsonValueConverter.cs
new file mode 100644
index 00000000000..f4952646b58
--- /dev/null
+++ b/mcs/class/System.Json.Microsoft/System.Json/JXmlToJsonValueConverter.cs
@@ -0,0 +1,304 @@
+// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
+
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Runtime.Serialization.Json;
+using System.Text;
+using System.Xml;
+
+namespace System.Json
+{
+ internal static class JXmlToJsonValueConverter
+ {
+ internal const string RootElementName = "root";
+ internal const string ItemElementName = "item";
+ internal const string TypeAttributeName = "type";
+ internal const string ArrayAttributeValue = "array";
+ internal const string BooleanAttributeValue = "boolean";
+ internal const string NullAttributeValue = "null";
+ internal const string NumberAttributeValue = "number";
+ internal const string ObjectAttributeValue = "object";
+ internal const string StringAttributeValue = "string";
+ private const string TypeHintAttributeName = "__type";
+
+ private static readonly char[] _floatingPointChars = new char[] { '.', 'e', 'E' };
+
+ public static JsonValue JXMLToJsonValue(Stream jsonStream)
+ {
+ if (jsonStream == null)
+ {
+ throw new ArgumentNullException("jsonStream");
+ }
+
+ return JXMLToJsonValue(jsonStream, null);
+ }
+
+ public static JsonValue JXMLToJsonValue(string jsonString)
+ {
+ if (jsonString == null)
+ {
+ throw new ArgumentNullException("jsonString");
+ }
+
+ if (jsonString.Length == 0)
+ {
+ throw new ArgumentException(Properties.Resources.JsonStringCannotBeEmpty, "jsonString");
+ }
+
+ byte[] jsonBytes = Encoding.UTF8.GetBytes(jsonString);
+
+ return JXMLToJsonValue(null, jsonBytes);
+ }
+
+ public static JsonValue JXMLToJsonValue(XmlDictionaryReader jsonReader)
+ {
+ if (jsonReader == null)
+ {
+ throw new ArgumentNullException("jsonReader");
+ }
+
+ const string RootObjectName = "RootObject";
+ Stack<JsonValue> jsonStack = new Stack<JsonValue>();
+ string nodeType = null;
+ bool isEmptyElement = false;
+
+ JsonValue parent = new JsonObject();
+ jsonStack.Push(parent);
+ string currentName = RootObjectName;
+
+ try
+ {
+ MoveToRootNode(jsonReader);
+
+ while (jsonStack.Count > 0 && jsonReader.NodeType != XmlNodeType.None)
+ {
+ if (parent is JsonObject && currentName == null)
+ {
+ currentName = GetMemberName(jsonReader);
+ }
+
+ nodeType = jsonReader.GetAttribute(TypeAttributeName) ?? StringAttributeValue;
+
+ if (parent is JsonArray)
+ {
+ // For arrays, the element name has to be "item"
+ if (jsonReader.Name != ItemElementName)
+ {
+ throw new FormatException(Properties.Resources.IncorrectJsonFormat);
+ }
+ }
+
+ switch (nodeType)
+ {
+ case NullAttributeValue:
+ case BooleanAttributeValue:
+ case StringAttributeValue:
+ case NumberAttributeValue:
+ JsonPrimitive jsonPrimitive = ReadPrimitive(nodeType, jsonReader);
+ InsertJsonValue(jsonStack, ref parent, ref currentName, jsonPrimitive, true);
+ break;
+ case ArrayAttributeValue:
+ JsonArray jsonArray = CreateJsonArray(jsonReader, ref isEmptyElement);
+ InsertJsonValue(jsonStack, ref parent, ref currentName, jsonArray, isEmptyElement);
+ break;
+ case ObjectAttributeValue:
+ JsonObject jsonObject = CreateObjectWithTypeHint(jsonReader, ref isEmptyElement);
+ InsertJsonValue(jsonStack, ref parent, ref currentName, jsonObject, isEmptyElement);
+ break;
+ default:
+ throw new FormatException(Properties.Resources.IncorrectJsonFormat);
+ }
+
+ while (jsonReader.NodeType == XmlNodeType.EndElement && jsonStack.Count > 0)
+ {
+ jsonReader.Read();
+ SkipWhitespace(jsonReader);
+ jsonStack.Pop();
+ if (jsonStack.Count > 0)
+ {
+ parent = jsonStack.Peek();
+ }
+ }
+ }
+ }
+ catch (XmlException xmlException)
+ {
+ throw new FormatException(Properties.Resources.IncorrectJsonFormat, xmlException);
+ }
+
+ if (jsonStack.Count != 1)
+ {
+ throw new FormatException(Properties.Resources.IncorrectJsonFormat);
+ }
+
+ return parent[RootObjectName];
+ }
+
+ private static JsonValue JXMLToJsonValue(Stream jsonStream, byte[] jsonBytes)
+ {
+ try
+ {
+ using (XmlDictionaryReader jsonReader =
+ jsonStream != null
+ ? JsonReaderWriterFactory.CreateJsonReader(jsonStream, XmlDictionaryReaderQuotas.Max)
+ : JsonReaderWriterFactory.CreateJsonReader(jsonBytes, XmlDictionaryReaderQuotas.Max))
+ {
+ return JXMLToJsonValue(jsonReader);
+ }
+ }
+ catch (XmlException)
+ {
+ throw new FormatException(Properties.Resources.IncorrectJsonFormat);
+ }
+ }
+
+ private static void InsertJsonValue(Stack<JsonValue> jsonStack, ref JsonValue parent, ref string currentName, JsonValue jsonValue, bool isEmptyElement)
+ {
+ if (parent is JsonArray)
+ {
+ ((JsonArray)parent).Add(jsonValue);
+ }
+ else
+ {
+ if (currentName != null)
+ {
+ ((JsonObject)parent)[currentName] = jsonValue;
+ currentName = null;
+ }
+ }
+
+ if (!isEmptyElement)
+ {
+ jsonStack.Push(jsonValue);
+ parent = jsonValue;
+ }
+ }
+
+ private static string GetMemberName(XmlDictionaryReader jsonReader)
+ {
+ string name;
+ if (jsonReader.NamespaceURI == ItemElementName && jsonReader.LocalName == ItemElementName)
+ {
+ // JXML special case for names which aren't valid XML names
+ name = jsonReader.GetAttribute(ItemElementName);
+
+ if (name == null)
+ {
+ throw new FormatException(Properties.Resources.IncorrectJsonFormat);
+ }
+ }
+ else
+ {
+ name = jsonReader.Name;
+ }
+
+ return name;
+ }
+
+ private static JsonObject CreateObjectWithTypeHint(XmlDictionaryReader jsonReader, ref bool isEmptyElement)
+ {
+ JsonObject jsonObject = new JsonObject();
+ string typeHintAttribute = jsonReader.GetAttribute(TypeHintAttributeName);
+ isEmptyElement = jsonReader.IsEmptyElement;
+ jsonReader.ReadStartElement();
+ SkipWhitespace(jsonReader);
+
+ if (typeHintAttribute != null)
+ {
+ jsonObject.Add(TypeHintAttributeName, typeHintAttribute);
+ }
+
+ return jsonObject;
+ }
+
+ private static JsonArray CreateJsonArray(XmlDictionaryReader jsonReader, ref bool isEmptyElement)
+ {
+ JsonArray jsonArray = new JsonArray();
+ isEmptyElement = jsonReader.IsEmptyElement;
+ jsonReader.ReadStartElement();
+ SkipWhitespace(jsonReader);
+ return jsonArray;
+ }
+
+ private static void MoveToRootNode(XmlDictionaryReader jsonReader)
+ {
+ while (!jsonReader.EOF && (jsonReader.NodeType == XmlNodeType.None || jsonReader.NodeType == XmlNodeType.XmlDeclaration))
+ {
+ // read into <root> node
+ jsonReader.Read();
+ SkipWhitespace(jsonReader);
+ }
+
+ if (jsonReader.NodeType != XmlNodeType.Element || !String.IsNullOrEmpty(jsonReader.NamespaceURI) || jsonReader.Name != RootElementName)
+ {
+ throw new FormatException(Properties.Resources.IncorrectJsonFormat);
+ }
+ }
+
+ private static JsonPrimitive ReadPrimitive(string type, XmlDictionaryReader jsonReader)
+ {
+ JsonValue result = null;
+ switch (type)
+ {
+ case NullAttributeValue:
+ jsonReader.Skip();
+ result = null;
+ break;
+ case BooleanAttributeValue:
+ result = jsonReader.ReadElementContentAsBoolean();
+ break;
+ case StringAttributeValue:
+ result = jsonReader.ReadElementContentAsString();
+ break;
+ case NumberAttributeValue:
+ string temp = jsonReader.ReadElementContentAsString();
+ result = ConvertStringToJsonNumber(temp);
+ break;
+ }
+
+ SkipWhitespace(jsonReader);
+ return (JsonPrimitive)result;
+ }
+
+ private static void SkipWhitespace(XmlDictionaryReader reader)
+ {
+ while (!reader.EOF && (reader.NodeType == XmlNodeType.Whitespace || reader.NodeType == XmlNodeType.SignificantWhitespace))
+ {
+ reader.Read();
+ }
+ }
+
+ private static JsonValue ConvertStringToJsonNumber(string value)
+ {
+ if (value.IndexOfAny(_floatingPointChars) < 0)
+ {
+ int intVal;
+ if (Int32.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out intVal))
+ {
+ return intVal;
+ }
+
+ long longVal;
+ if (Int64.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out longVal))
+ {
+ return longVal;
+ }
+ }
+
+ decimal decValue;
+ if (Decimal.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out decValue) && decValue != 0)
+ {
+ return decValue;
+ }
+
+ double dblValue;
+ if (Double.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out dblValue))
+ {
+ return dblValue;
+ }
+
+ throw new ArgumentException(RS.Format(Properties.Resources.InvalidJsonPrimitive, value.ToString()), "value");
+ }
+ }
+}
diff --git a/mcs/class/System.Json.Microsoft/System.Json/JsonArray.cs b/mcs/class/System.Json.Microsoft/System.Json/JsonArray.cs
new file mode 100644
index 00000000000..21d0d03e5ca
--- /dev/null
+++ b/mcs/class/System.Json.Microsoft/System.Json/JsonArray.cs
@@ -0,0 +1,389 @@
+// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
+
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Globalization;
+using System.Runtime.Serialization;
+using System.Xml;
+
+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));
+ }
+ }
+ }
+}
diff --git a/mcs/class/System.Json.Microsoft/System.Json/JsonObject.cs b/mcs/class/System.Json.Microsoft/System.Json/JsonObject.cs
new file mode 100644
index 00000000000..a8831c64648
--- /dev/null
+++ b/mcs/class/System.Json.Microsoft/System.Json/JsonObject.cs
@@ -0,0 +1,474 @@
+// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
+
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.Serialization;
+using System.Xml;
+using WrappedPair = System.Json.NGenWrapper<System.Collections.Generic.KeyValuePair<string, System.Json.JsonValue>>;
+
+namespace System.Json
+{
+ /// <summary>
+ /// A JsonObject is an unordered collection of zero or more key/value pairs.
+ /// </summary>
+ /// <remarks>A JsonObject is an unordered collection of zero or more key/value pairs,
+ /// where each key is a String and each value is a <see cref="System.Json.JsonValue"/>, which can be a
+ /// <see cref="System.Json.JsonPrimitive"/>, a <see cref="System.Json.JsonArray"/>, or a JsonObject.</remarks>
+ [SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix",
+ Justification = "Object in the context of JSON already conveys the meaning of dictionary")]
+ [DataContract]
+ public sealed class JsonObject : JsonValue, IDictionary<string, JsonValue>
+ {
+ [DataMember]
+ private Dictionary<string, JsonValue> values = new Dictionary<string, JsonValue>(StringComparer.Ordinal);
+
+ private List<WrappedPair> indexedPairs;
+ private int instanceSaveCount;
+ private object saveLock = new object();
+
+ /// <summary>
+ /// Creates an instance of the <see cref="System.Json.JsonObject"/> class initialized with an
+ /// <see cref="System.Collections.Generic.IEnumerable{T}"/> collection of key/value pairs.
+ /// </summary>
+ /// <param name="items">The <see cref="System.Collections.Generic.IEnumerable{T}"/> collection of
+ /// <see cref="System.Collections.Generic.KeyValuePair{K, V}"/> used to initialize the
+ /// key/value pairs</param>
+ /// <exception cref="System.ArgumentNullException">If items is null.</exception>
+ /// <exception cref="System.ArgumentException">If any of the values 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>
+ [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures",
+ Justification = "There's no complexity using this design because nested generic type is atomic type not another collection")]
+ public JsonObject(IEnumerable<KeyValuePair<string, JsonValue>> items)
+ {
+ AddRange(items);
+ }
+
+ /// <summary>
+ /// Creates an instance of the <see cref="System.Json.JsonObject"/> class initialized with a collection of key/value pairs.
+ /// </summary>
+ /// <param name="items">The <see cref="System.Collections.Generic.KeyValuePair{K, V}"/> objects used to initialize the key/value pairs.</param>
+ /// <exception cref="System.ArgumentException">If any of the values 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 JsonObject(params KeyValuePair<string, JsonValue>[] items)
+ {
+ if (items != null)
+ {
+ AddRange(items);
+ }
+ }
+
+ /// <summary>
+ /// Gets the JSON type of this <see cref="System.Json.JsonObject"/>. The return value
+ /// is always <see cref="F:System.Json.JsonType.Object"/>.
+ /// </summary>
+ public override JsonType JsonType
+ {
+ get { return JsonType.Object; }
+ }
+
+ /// <summary>
+ /// Gets a collection that contains the keys in this <see cref="System.Json.JsonObject"/>.
+ /// </summary>
+ public ICollection<string> Keys
+ {
+ get { return values.Keys; }
+ }
+
+ /// <summary>
+ /// Gets a collection that contains the values in this <see cref="System.Json.JsonObject"/>.
+ /// </summary>
+ public ICollection<JsonValue> Values
+ {
+ get { return values.Values; }
+ }
+
+ /// <summary>
+ /// Returns the number of key/value pairs in this <see cref="System.Json.JsonObject"/>.
+ /// </summary>
+ public override int Count
+ {
+ get { return values.Count; }
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether this JSON CLR object is read-only.
+ /// </summary>
+ bool ICollection<KeyValuePair<string, JsonValue>>.IsReadOnly
+ {
+ get { return ((ICollection<KeyValuePair<string, JsonValue>>)values).IsReadOnly; }
+ }
+
+ /// <summary>
+ /// Gets or sets the value associated with the specified key.
+ /// </summary>
+ /// <param name="key">The key of the value to get or set.</param>
+ /// <returns>The <see cref="System.Json.JsonValue"/> associated to the specified key.</returns>
+ /// <exception cref="System.ArgumentNullException">If key is null.</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[string key]
+ {
+ get
+ {
+ if (key == null)
+ {
+ throw new ArgumentNullException("key");
+ }
+
+ return values[key];
+ }
+
+ set
+ {
+ if (value != null && value.JsonType == JsonType.Default)
+ {
+ throw new ArgumentNullException("value", Properties.Resources.UseOfDefaultNotAllowed);
+ }
+
+ if (key == null)
+ {
+ throw new ArgumentNullException("key");
+ }
+
+ bool replacement = values.ContainsKey(key);
+ JsonValue oldValue = null;
+ if (replacement)
+ {
+ oldValue = values[key];
+ RaiseItemChanging(value, JsonValueChange.Replace, key);
+ }
+ else
+ {
+ RaiseItemChanging(value, JsonValueChange.Add, key);
+ }
+
+ values[key] = value;
+ if (replacement)
+ {
+ RaiseItemChanged(oldValue, JsonValueChange.Replace, key);
+ }
+ else
+ {
+ RaiseItemChanged(value, JsonValueChange.Add, key);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Safe string indexer for the <see cref="System.Json.JsonValue"/> type.
+ /// </summary>
+ /// <param name="key">The key of the element to get.</param>
+ /// <returns>If this instance contains the given key and the value corresponding to
+ /// the key 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(string key)
+ {
+ if (key != null && ContainsKey(key) && this[key] != null)
+ {
+ return this[key];
+ }
+
+ return base.ValueOrDefault(key);
+ }
+
+ /// <summary>
+ /// Adds a specified collection of key/value pairs to this instance.
+ /// </summary>
+ /// <param name="items">The collection of key/value pairs to add.</param>
+ /// <exception cref="System.ArgumentNullException">If items is null.</exception>
+ /// <exception cref="System.ArgumentException">If the value of 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>
+ [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures",
+ Justification = "There's no complexity using this design because nested generic type is atomic type not another collection")]
+ public void AddRange(IEnumerable<KeyValuePair<string, JsonValue>> items)
+ {
+ if (items == null)
+ {
+ throw new ArgumentNullException("items");
+ }
+
+ if (ChangingListenersCount > 0)
+ {
+ foreach (KeyValuePair<string, JsonValue> item in items)
+ {
+ RaiseItemChanging(item.Value, JsonValueChange.Add, item.Key);
+ }
+ }
+
+ foreach (KeyValuePair<string, JsonValue> item in items)
+ {
+ if (item.Value != null && item.Value.JsonType == JsonType.Default)
+ {
+ throw new ArgumentNullException("items", Properties.Resources.UseOfDefaultNotAllowed);
+ }
+
+ values.Add(item.Key, item.Value);
+ RaiseItemChanged(item.Value, JsonValueChange.Add, item.Key);
+ }
+ }
+
+ /// <summary>
+ /// Adds the elements from an array of type <see cref="System.Json.JsonValue"/> to this instance.
+ /// </summary>
+ /// <param name="items">The array of key/value paris to be added to this instance.</param>
+ /// <exception cref="System.ArgumentException">If the value of 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 KeyValuePair<string, JsonValue>[] items)
+ {
+ AddRange(items as IEnumerable<KeyValuePair<string, JsonValue>>);
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return ((IEnumerable)values).GetEnumerator();
+ }
+
+ /// <summary>
+ /// Adds a key/value pair to this <see cref="System.Json.JsonObject"/> instance.
+ /// </summary>
+ /// <param name="key">The key for the element added.</param>
+ /// <param name="value">The <see cref="System.Json.JsonValue"/> for the element added.</param>
+ /// <exception cref="System.ArgumentException">If 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 void Add(string key, JsonValue value)
+ {
+ if (value != null && value.JsonType == JsonType.Default)
+ {
+ throw new ArgumentNullException("value", Properties.Resources.UseOfDefaultNotAllowed);
+ }
+
+ RaiseItemChanging(value, JsonValueChange.Add, key);
+ values.Add(key, value);
+ RaiseItemChanged(value, JsonValueChange.Add, key);
+ }
+
+ /// <summary>
+ /// Adds a key/value pair to this <see cref="System.Json.JsonObject"/> instance.
+ /// </summary>
+ /// <param name="item">The key/value pair to be added.</param>
+ /// <exception cref="System.ArgumentException">If the value of the pair 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 Add(KeyValuePair<string, JsonValue> item)
+ {
+ Add(item.Key, item.Value);
+ }
+
+ /// <summary>
+ /// Checks whether a key/value pair with a specified key exists in this <see cref="System.Json.JsonObject"/> instance.
+ /// </summary>
+ /// <param name="key">The key to check for.</param>
+ /// <returns>true if this instance contains the key; otherwise, false.</returns>
+ public override bool ContainsKey(string key)
+ {
+ return values.ContainsKey(key);
+ }
+
+ /// <summary>
+ /// Removes the key/value pair with a specified key from this <see cref="System.Json.JsonObject"/> instance.
+ /// </summary>
+ /// <param name="key">The key of the item to remove.</param>
+ /// <returns>true if the element is successfully found and removed; otherwise, false.
+ /// This method returns false if key is not found in this <see cref="System.Json.JsonObject"/> instance.</returns>
+ public bool Remove(string key)
+ {
+ JsonValue original = null;
+ bool containsKey = false;
+ if (ChangingListenersCount > 0 || ChangedListenersCount > 0)
+ {
+ containsKey = TryGetValue(key, out original);
+ }
+
+ if (containsKey && ChangingListenersCount > 0)
+ {
+ RaiseItemChanging(original, JsonValueChange.Remove, key);
+ }
+
+ bool result = values.Remove(key);
+
+ if (containsKey && ChangedListenersCount > 0)
+ {
+ RaiseItemChanged(original, JsonValueChange.Remove, key);
+ }
+
+ return result;
+ }
+
+ /// <summary>
+ /// Attempts to get the value that corresponds to the specified key.
+ /// </summary>
+ /// <param name="key">The key of the value to retrieve.</param>
+ /// <param name="value">The primitive or structured <see cref="System.Json.JsonValue"/> object that has the key
+ /// specified. If this object does not contain a key/value pair with the given key,
+ /// this parameter is set to null.</param>
+ /// <returns>true if the instance of the <see cref="System.Json.JsonObject"/> contains an element with the
+ /// specified key; otherwise, false.</returns>
+ public bool TryGetValue(string key, out JsonValue value)
+ {
+ return values.TryGetValue(key, out value);
+ }
+
+ /// <summary>
+ /// Removes all key/value pairs from this <see cref="System.Json.JsonObject"/> instance.
+ /// </summary>
+ public void Clear()
+ {
+ RaiseItemChanging(null, JsonValueChange.Clear, null);
+ values.Clear();
+ RaiseItemChanged(null, JsonValueChange.Clear, null);
+ }
+
+ bool ICollection<KeyValuePair<string, JsonValue>>.Contains(KeyValuePair<string, JsonValue> item)
+ {
+ return ((ICollection<KeyValuePair<string, JsonValue>>)values).Contains(item);
+ }
+
+ /// <summary>
+ /// Copies the contents of this <see cref="System.Json.JsonObject"/> instance into a specified
+ /// key/value destination array beginning at a specified index.
+ /// </summary>
+ /// <param name="array">The destination array of type <see cref="System.Collections.Generic.KeyValuePair{K, V}"/>
+ /// to which the elements of this <see cref="System.Json.JsonObject"/> are copied.</param>
+ /// <param name="arrayIndex">The zero-based index at which to begin the insertion of the
+ /// contents from this <see cref="System.Json.JsonObject"/> instance.</param>
+ public void CopyTo(KeyValuePair<string, JsonValue>[] array, int arrayIndex)
+ {
+ ((ICollection<KeyValuePair<string, JsonValue>>)values).CopyTo(array, arrayIndex);
+ }
+
+ bool ICollection<KeyValuePair<string, JsonValue>>.Remove(KeyValuePair<string, JsonValue> item)
+ {
+ if (ChangingListenersCount > 0)
+ {
+ if (ContainsKey(item.Key) && EqualityComparer<JsonValue>.Default.Equals(item.Value, values[item.Key]))
+ {
+ RaiseItemChanging(item.Value, JsonValueChange.Remove, item.Key);
+ }
+ }
+
+ bool result = ((ICollection<KeyValuePair<string, JsonValue>>)values).Remove(item);
+ if (result)
+ {
+ RaiseItemChanged(item.Value, JsonValueChange.Remove, item.Key);
+ }
+
+ return result;
+ }
+
+ /// <summary>
+ /// Returns an enumerator over the key/value pairs contained in this <see cref="System.Json.JsonObject"/> instance.
+ /// </summary>
+ /// <returns>An <see cref="System.Collections.Generic.IEnumerator{T}"/> which iterates
+ /// through the members of this instance.</returns>
+ protected override IEnumerator<KeyValuePair<string, JsonValue>> GetKeyValuePairEnumerator()
+ {
+ return values.GetEnumerator();
+ }
+
+ /// <summary>
+ /// Callback method called when a Save operation is starting for this instance.
+ /// </summary>
+ protected override void OnSaveStarted()
+ {
+ lock (saveLock)
+ {
+ instanceSaveCount++;
+ if (indexedPairs == null)
+ {
+ indexedPairs = new List<WrappedPair>();
+
+ foreach (KeyValuePair<string, JsonValue> item in values)
+ {
+ indexedPairs.Add(new WrappedPair(item));
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// Callback method called when a Save operation is finished for this instance.
+ /// </summary>
+ protected override void OnSaveEnded()
+ {
+ lock (saveLock)
+ {
+ instanceSaveCount--;
+ if (instanceSaveCount == 0)
+ {
+ indexedPairs = null;
+ }
+ }
+ }
+
+ /// <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)
+ {
+ jsonWriter.WriteAttributeString(JXmlToJsonValueConverter.TypeAttributeName, JXmlToJsonValueConverter.ObjectAttributeValue);
+ }
+
+ /// <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)
+ {
+ KeyValuePair<string, JsonValue> currentPair = indexedPairs[currentIndex];
+ string currentKey = currentPair.Key;
+
+ if (currentKey.Length == 0)
+ {
+ // special case in JXML world
+ jsonWriter.WriteStartElement(JXmlToJsonValueConverter.ItemElementName, JXmlToJsonValueConverter.ItemElementName);
+ jsonWriter.WriteAttributeString(JXmlToJsonValueConverter.ItemElementName, String.Empty);
+ }
+ else
+ {
+ jsonWriter.WriteStartElement(currentKey);
+ }
+
+ return currentPair.Value;
+ }
+
+ [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", Justification = "Context is required by CLR for this to work.")]
+ [OnDeserialized]
+ private void OnDeserialized(StreamingContext context)
+ {
+ saveLock = new object();
+ }
+
+ private void RaiseItemChanging(JsonValue child, JsonValueChange change, string key)
+ {
+ if (ChangingListenersCount > 0)
+ {
+ RaiseChangingEvent(this, new JsonValueChangeEventArgs(child, change, key));
+ }
+ }
+
+ private void RaiseItemChanged(JsonValue child, JsonValueChange change, string key)
+ {
+ if (ChangedListenersCount > 0)
+ {
+ RaiseChangedEvent(this, new JsonValueChangeEventArgs(child, change, key));
+ }
+ }
+ }
+}
diff --git a/mcs/class/System.Json.Microsoft/System.Json/JsonPrimitive.cs b/mcs/class/System.Json.Microsoft/System.Json/JsonPrimitive.cs
new file mode 100644
index 00000000000..6d5cc7c520f
--- /dev/null
+++ b/mcs/class/System.Json.Microsoft/System.Json/JsonPrimitive.cs
@@ -0,0 +1,1151 @@
+// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
+
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Diagnostics.Contracts;
+using System.Globalization;
+using System.Runtime.Serialization;
+using System.Text;
+using System.Xml;
+
+namespace System.Json
+{
+ /// <summary>
+ /// Represents a JavaScript Object Notation (JSON) primitive type in the common language runtime (CLR).
+ /// </summary>
+ [SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix",
+ Justification = "JsonPrimitive does not represent a collection.")]
+ [DataContract]
+ public sealed class JsonPrimitive : JsonValue
+ {
+ internal const string DateTimeIsoFormat = "yyyy-MM-ddTHH:mm:ss.fffK";
+ private const string UtcString = "UTC";
+ private const string GmtString = "GMT";
+ private static readonly long UnixEpochTicks = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks;
+ private static readonly char[] FloatingPointChars = new char[] { '.', 'e', 'E' };
+ private static readonly Type jsonPrimitiveType = typeof(JsonPrimitive);
+ private static readonly Type uriType = typeof(Uri);
+
+ private static readonly Dictionary<Type, Func<string, ConvertResult>> stringConverters = new Dictionary<Type, Func<string, ConvertResult>>
+ {
+ { typeof(bool), new Func<string, ConvertResult>(StringToBool) },
+ { typeof(byte), new Func<string, ConvertResult>(StringToByte) },
+ { typeof(char), new Func<string, ConvertResult>(StringToChar) },
+ { typeof(sbyte), new Func<string, ConvertResult>(StringToSByte) },
+ { typeof(short), new Func<string, ConvertResult>(StringToShort) },
+ { typeof(int), new Func<string, ConvertResult>(StringToInt) },
+ { typeof(long), new Func<string, ConvertResult>(StringToLong) },
+ { typeof(ushort), new Func<string, ConvertResult>(StringToUShort) },
+ { typeof(uint), new Func<string, ConvertResult>(StringToUInt) },
+ { typeof(ulong), new Func<string, ConvertResult>(StringToULong) },
+ { typeof(float), new Func<string, ConvertResult>(StringToFloat) },
+ { typeof(double), new Func<string, ConvertResult>(StringToDouble) },
+ { typeof(decimal), new Func<string, ConvertResult>(StringToDecimal) },
+ { typeof(DateTime), new Func<string, ConvertResult>(StringToDateTime) },
+ { typeof(DateTimeOffset), new Func<string, ConvertResult>(StringToDateTimeOffset) },
+ { typeof(Guid), new Func<string, ConvertResult>(StringToGuid) },
+ { typeof(Uri), new Func<string, ConvertResult>(StringToUri) },
+ };
+
+ [DataMember]
+ private object value;
+
+ [DataMember]
+ private JsonType jsonType;
+
+ /// <summary>
+ /// Initializes a new instance of a <see cref="System.Json.JsonPrimitive"/> type with a <see cref="System.Boolean"/> type.
+ /// </summary>
+ /// <param name="value">The <see cref="System.Boolean"/> object that initializes the new instance.</param>
+ /// <remarks>A <see cref="System.Json.JsonPrimitive"/> object stores a <see cref="System.Json.JsonType"/> and the value used to initialize it.
+ /// When initialized with a <see cref="System.Boolean"/> object, the <see cref="System.Json.JsonType"/> is a <see cref="F:System.Json.JsonType.Boolean"/>, which can be
+ /// recovered using the <see cref="System.Json.JsonPrimitive.JsonType"/> property. The value used to initialize the <see cref="System.Json.JsonPrimitive"/>
+ /// object can be recovered by casting the <see cref="System.Json.JsonPrimitive"/> to <see cref="System.Boolean"/>.</remarks>
+ public JsonPrimitive(bool value)
+ {
+ jsonType = JsonType.Boolean;
+ this.value = value;
+ }
+
+ /// <summary>
+ /// Initializes a new instance of a <see cref="System.Json.JsonPrimitive"/> type with a <see cref="System.Byte"/> type.
+ /// </summary>
+ /// <param name="value">The <see cref="System.Byte"/> object that initializes the new instance.</param>
+ /// <remarks>A <see cref="System.Json.JsonPrimitive"/> object stores a <see cref="System.Json.JsonType"/> and the value used to initialize it.
+ /// When initialized with a <see cref="System.Byte"/> object, the <see cref="System.Json.JsonType"/> is a <see cref="F:System.Json.JsonType.Number"/>, which can be
+ /// recovered using the <see cref="System.Json.JsonPrimitive.JsonType"/> property. The value used to initialize the <see cref="System.Json.JsonPrimitive"/>
+ /// object can be recovered by casting the <see cref="System.Json.JsonPrimitive"/> to <see cref="System.Byte"/>.</remarks>
+ public JsonPrimitive(byte value)
+ {
+ jsonType = JsonType.Number;
+ this.value = value;
+ }
+
+ /// <summary>
+ /// Initializes a new instance of a <see cref="System.Json.JsonPrimitive"/> type with a <see cref="System.SByte"/> type.
+ /// </summary>
+ /// <param name="value">The <see cref="System.SByte"/> object that initializes the new instance.</param>
+ /// <remarks>A <see cref="System.Json.JsonPrimitive"/> object stores a <see cref="System.Json.JsonType"/> and the value used to initialize it.
+ /// When initialized with a <see cref="System.SByte"/> object, the <see cref="System.Json.JsonType"/> is a <see cref="F:System.Json.JsonType.Number"/>, which can be
+ /// recovered using the <see cref="System.Json.JsonPrimitive.JsonType"/> property. The value used to initialize the <see cref="System.Json.JsonPrimitive"/>
+ /// object can be recovered by casting the <see cref="System.Json.JsonPrimitive"/> to <see cref="System.SByte"/>.</remarks>
+ [CLSCompliant(false)]
+ public JsonPrimitive(sbyte value)
+ {
+ jsonType = JsonType.Number;
+ this.value = value;
+ }
+
+ /// <summary>
+ /// Initializes a new instance of a <see cref="System.Json.JsonPrimitive"/> type with a <see cref="System.Decimal"/> type.
+ /// </summary>
+ /// <param name="value">The <see cref="System.Decimal"/> object that initializes the new instance.</param>
+ /// <remarks>A <see cref="System.Json.JsonPrimitive"/> object stores a <see cref="System.Json.JsonType"/> and the value used to initialize it.
+ /// When initialized with a <see cref="System.Decimal"/> object, the <see cref="System.Json.JsonType"/> is a <see cref="F:System.Json.JsonType.Number"/>, which can be
+ /// recovered using the <see cref="System.Json.JsonPrimitive.JsonType"/> property. The value used to initialize the <see cref="System.Json.JsonPrimitive"/>
+ /// object can be recovered by casting the <see cref="System.Json.JsonPrimitive"/> to <see cref="System.Decimal"/>.</remarks>
+ public JsonPrimitive(decimal value)
+ {
+ jsonType = JsonType.Number;
+ this.value = value;
+ }
+
+ /// <summary>
+ /// Initializes a new instance of a <see cref="System.Json.JsonPrimitive"/> type with a <see cref="System.Int16"/> type.
+ /// </summary>
+ /// <param name="value">The <see cref="System.Int16"/> object that initializes the new instance.</param>
+ /// <remarks>A <see cref="System.Json.JsonPrimitive"/> object stores a <see cref="System.Json.JsonType"/> and the value used to initialize it.
+ /// When initialized with a <see cref="System.Int16"/> object, the <see cref="System.Json.JsonType"/> is a <see cref="F:System.Json.JsonType.Number"/>, which can be
+ /// recovered using the <see cref="System.Json.JsonPrimitive.JsonType"/> property. The value used to initialize the <see cref="System.Json.JsonPrimitive"/>
+ /// object can be recovered by casting the <see cref="System.Json.JsonPrimitive"/> to <see cref="System.Int16"/>.</remarks>
+ public JsonPrimitive(short value)
+ {
+ jsonType = JsonType.Number;
+ this.value = value;
+ }
+
+ /// <summary>
+ /// Initializes a new instance of a <see cref="System.Json.JsonPrimitive"/> type with a <see cref="System.UInt16"/> type.
+ /// </summary>
+ /// <param name="value">The <see cref="System.UInt16"/> object that initializes the new instance.</param>
+ /// <remarks>A <see cref="System.Json.JsonPrimitive"/> object stores a <see cref="System.Json.JsonType"/> and the value used to initialize it.
+ /// When initialized with a <see cref="System.UInt16"/> object, the <see cref="System.Json.JsonType"/> is a <see cref="F:System.Json.JsonType.Number"/>, which can be
+ /// recovered using the <see cref="System.Json.JsonPrimitive.JsonType"/> property. The value used to initialize the <see cref="System.Json.JsonPrimitive"/>
+ /// object can be recovered by casting the <see cref="System.Json.JsonPrimitive"/> to <see cref="System.UInt16"/>.</remarks>
+ [CLSCompliant(false)]
+ public JsonPrimitive(ushort value)
+ {
+ jsonType = JsonType.Number;
+ this.value = value;
+ }
+
+ /// <summary>
+ /// Initializes a new instance of a <see cref="System.Json.JsonPrimitive"/> type with a <see cref="System.Int32"/> type.
+ /// </summary>
+ /// <param name="value">The <see cref="System.Int32"/> object that initializes the new instance.</param>
+ /// <remarks>A <see cref="System.Json.JsonPrimitive"/> object stores a <see cref="System.Json.JsonType"/> and the value used to initialize it.
+ /// When initialized with a <see cref="System.Int32"/> object, the <see cref="System.Json.JsonType"/> is a <see cref="F:System.Json.JsonType.Number"/>, which can be
+ /// recovered using the <see cref="System.Json.JsonPrimitive.JsonType"/> property. The value used to initialize the <see cref="System.Json.JsonPrimitive"/>
+ /// object can be recovered by casting the <see cref="System.Json.JsonPrimitive"/> to <see cref="System.Int32"/>.</remarks>
+ public JsonPrimitive(int value)
+ {
+ jsonType = JsonType.Number;
+ this.value = value;
+ }
+
+ /// <summary>
+ /// Initializes a new instance of a <see cref="System.Json.JsonPrimitive"/> type with a <see cref="System.UInt32"/> type.
+ /// </summary>
+ /// <param name="value">The <see cref="System.UInt32"/> object that initializes the new instance.</param>
+ /// <remarks>A <see cref="System.Json.JsonPrimitive"/> object stores a <see cref="System.Json.JsonType"/> and the value used to initialize it.
+ /// When initialized with a <see cref="System.UInt32"/> object, the <see cref="System.Json.JsonType"/> is a <see cref="F:System.Json.JsonType.Number"/>, which can be
+ /// recovered using the <see cref="System.Json.JsonPrimitive.JsonType"/> property. The value used to initialize the <see cref="System.Json.JsonPrimitive"/>
+ /// object can be recovered by casting the <see cref="System.Json.JsonPrimitive"/> to <see cref="System.UInt32"/>.</remarks>
+ [CLSCompliant(false)]
+ public JsonPrimitive(uint value)
+ {
+ jsonType = JsonType.Number;
+ this.value = value;
+ }
+
+ /// <summary>
+ /// Initializes a new instance of a <see cref="System.Json.JsonPrimitive"/> type with a <see cref="System.Int64"/> type.
+ /// </summary>
+ /// <param name="value">The <see cref="System.Int64"/> object that initializes the new instance.</param>
+ /// <remarks>A <see cref="System.Json.JsonPrimitive"/> object stores a <see cref="System.Json.JsonType"/> and the value used to initialize it.
+ /// When initialized with a <see cref="System.Int64"/> object, the <see cref="System.Json.JsonType"/> is a <see cref="F:System.Json.JsonType.Number"/>, which can be
+ /// recovered using the <see cref="System.Json.JsonPrimitive.JsonType"/> property. The value used to initialize the <see cref="System.Json.JsonPrimitive"/>
+ /// object can be recovered by casting the <see cref="System.Json.JsonPrimitive"/> to <see cref="System.Int64"/>.</remarks>
+ public JsonPrimitive(long value)
+ {
+ jsonType = JsonType.Number;
+ this.value = value;
+ }
+
+ /// <summary>
+ /// Initializes a new instance of a <see cref="System.Json.JsonPrimitive"/> type with a <see cref="System.UInt64"/> type.
+ /// </summary>
+ /// <param name="value">The <see cref="System.UInt64"/> object that initializes the new instance.</param>
+ /// <remarks>A <see cref="System.Json.JsonPrimitive"/> object stores a <see cref="System.Json.JsonType"/> and the value used to initialize it.
+ /// When initialized with a <see cref="System.UInt64"/> object, the <see cref="System.Json.JsonType"/> is a <see cref="F:System.Json.JsonType.Number"/>, which can be
+ /// recovered using the <see cref="System.Json.JsonPrimitive.JsonType"/> property. The value used to initialize the <see cref="System.Json.JsonPrimitive"/>
+ /// object can be recovered by casting the <see cref="System.Json.JsonPrimitive"/> to <see cref="System.UInt64"/>.</remarks>
+ [CLSCompliant(false)]
+ public JsonPrimitive(ulong value)
+ {
+ jsonType = JsonType.Number;
+ this.value = value;
+ }
+
+ /// <summary>
+ /// Initializes a new instance of a <see cref="System.Json.JsonPrimitive"/> type with a <see cref="System.Single"/> type.
+ /// </summary>
+ /// <param name="value">The <see cref="System.Single"/> object that initializes the new instance.</param>
+ /// <remarks>A <see cref="System.Json.JsonPrimitive"/> object stores a <see cref="System.Json.JsonType"/> and the value used to initialize it.
+ /// When initialized with a <see cref="System.Single"/> object, the <see cref="System.Json.JsonType"/> is a <see cref="F:System.Json.JsonType.Number"/>, which can be
+ /// recovered using the <see cref="System.Json.JsonPrimitive.JsonType"/> property. The value used to initialize the <see cref="System.Json.JsonPrimitive"/>
+ /// object can be recovered by casting the <see cref="System.Json.JsonPrimitive"/> to <see cref="System.Single"/>.</remarks>
+ public JsonPrimitive(float value)
+ {
+ jsonType = JsonType.Number;
+ this.value = value;
+ }
+
+ /// <summary>
+ /// Initializes a new instance of a <see cref="System.Json.JsonPrimitive"/> type with a <see cref="System.Double"/> type.
+ /// </summary>
+ /// <param name="value">The <see cref="System.Double"/> object that initializes the new instance.</param>
+ /// <remarks>A <see cref="System.Json.JsonPrimitive"/> object stores a <see cref="System.Json.JsonType"/> and the value used to initialize it.
+ /// When initialized with a <see cref="System.Double"/> object, the <see cref="System.Json.JsonType"/> is a <see cref="F:System.Json.JsonType.Number"/>, which can be
+ /// recovered using the <see cref="System.Json.JsonPrimitive.JsonType"/> property. The value used to initialize the <see cref="System.Json.JsonPrimitive"/>
+ /// object can be recovered by casting the <see cref="System.Json.JsonPrimitive"/> to <see cref="System.Double"/>.</remarks>
+ public JsonPrimitive(double value)
+ {
+ jsonType = JsonType.Number;
+ this.value = value;
+ }
+
+ /// <summary>
+ /// Initializes a new instance of a <see cref="System.Json.JsonPrimitive"/> type with a <see cref="System.String"/> type.
+ /// </summary>
+ /// <param name="value">The <see cref="System.String"/> object that initializes the new instance.</param>
+ /// <remarks>A <see cref="System.Json.JsonPrimitive"/> object stores a <see cref="System.Json.JsonType"/> and the value used to initialize it.
+ /// When initialized with a <see cref="System.String"/> object, the <see cref="System.Json.JsonType"/> is a <see cref="F:System.Json.JsonType.String"/>, which can be
+ /// recovered using the <see cref="System.Json.JsonPrimitive.JsonType"/> property. The value used to initialize the <see cref="System.Json.JsonPrimitive"/>
+ /// object can be recovered by casting the <see cref="System.Json.JsonPrimitive"/> to <see cref="System.String"/>.</remarks>
+ /// <exception cref="System.ArgumentNullException">value is null.</exception>
+ [SuppressMessage("Microsoft.Design", "CA1057:StringUriOverloadsCallSystemUriOverloads",
+ Justification = "This operator does not intend to represent a Uri overload.")]
+ public JsonPrimitive(string value)
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException("value");
+ }
+
+ jsonType = JsonType.String;
+ this.value = value;
+ }
+
+ /// <summary>
+ /// Initializes a new instance of a <see cref="System.Json.JsonPrimitive"/> type with a <see cref="System.Char"/> type.
+ /// </summary>
+ /// <param name="value">The <see cref="System.Char"/> object that initializes the new instance.</param>
+ /// <remarks>A <see cref="System.Json.JsonPrimitive"/> object stores a <see cref="System.Json.JsonType"/> and the value used to initialize it.
+ /// When initialized with a <see cref="System.Char"/> object, the <see cref="System.Json.JsonType"/> is a <see cref="F:System.Json.JsonType.String"/>, which can be
+ /// recovered using the <see cref="System.Json.JsonPrimitive.JsonType"/> property. The value used to initialize the <see cref="System.Json.JsonPrimitive"/>
+ /// object can be recovered by casting the <see cref="System.Json.JsonPrimitive"/> to <see cref="System.Char"/>.</remarks>
+ public JsonPrimitive(char value)
+ {
+ jsonType = JsonType.String;
+ this.value = value;
+ }
+
+ /// <summary>
+ /// Initializes a new instance of a <see cref="System.Json.JsonPrimitive"/> type with a <see cref="System.DateTime"/> type.
+ /// </summary>
+ /// <param name="value">The <see cref="System.DateTime"/> object that initializes the new instance.</param>
+ /// <remarks>A <see cref="System.Json.JsonPrimitive"/> object stores a <see cref="System.Json.JsonType"/> and the value used to initialize it.
+ /// When initialized with a <see cref="System.DateTime"/> object, the <see cref="System.Json.JsonType"/> is a <see cref="F:System.Json.JsonType.String"/>, which can be
+ /// recovered using the <see cref="System.Json.JsonPrimitive.JsonType"/> property. The value used to initialize the <see cref="System.Json.JsonPrimitive"/>
+ /// object can be recovered by casting the <see cref="System.Json.JsonPrimitive"/> to <see cref="System.DateTime"/>.</remarks>
+ public JsonPrimitive(DateTime value)
+ {
+ jsonType = JsonType.String;
+ this.value = value;
+ }
+
+ /// <summary>
+ /// Initializes a new instance of a <see cref="System.Json.JsonPrimitive"/> type with a <see cref="System.DateTimeOffset"/> type.
+ /// </summary>
+ /// <param name="value">The <see cref="System.DateTimeOffset"/> object that initializes the new instance.</param>
+ /// <remarks>A <see cref="System.Json.JsonPrimitive"/> object stores a <see cref="System.Json.JsonType"/> and the value used to initialize it.
+ /// When initialized with a <see cref="System.DateTimeOffset"/> object, the <see cref="System.Json.JsonType"/> is a <see cref="F:System.Json.JsonType.String"/>, which can be
+ /// recovered using the <see cref="System.Json.JsonPrimitive.JsonType"/> property. The value used to initialize the <see cref="System.Json.JsonPrimitive"/>
+ /// object can be recovered by casting the <see cref="System.Json.JsonPrimitive"/> to <see cref="System.DateTimeOffset"/>.</remarks>
+ public JsonPrimitive(DateTimeOffset value)
+ {
+ jsonType = JsonType.String;
+ this.value = value;
+ }
+
+ /// <summary>
+ /// Initializes a new instance of a <see cref="System.Json.JsonPrimitive"/> type with a <see cref="System.Uri"/> type.
+ /// </summary>
+ /// <param name="value">The <see cref="System.Uri"/> object that initializes the new instance.</param>
+ /// <remarks>A <see cref="System.Json.JsonPrimitive"/> object stores a <see cref="System.Json.JsonType"/> and the value used to initialize it.
+ /// When initialized with a <see cref="System.Uri"/> object, the <see cref="System.Json.JsonType"/> is a <see cref="F:System.Json.JsonType.String"/>, which can be
+ /// recovered using the <see cref="System.Json.JsonPrimitive.JsonType"/> property. The value used to initialize the <see cref="System.Json.JsonPrimitive"/>
+ /// object can be recovered by casting the <see cref="System.Json.JsonPrimitive"/> to <see cref="System.Uri"/>.</remarks>
+ /// <exception cref="System.ArgumentNullException">value is null.</exception>
+ public JsonPrimitive(Uri value)
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException("value");
+ }
+
+ jsonType = JsonType.String;
+ this.value = value;
+ }
+
+ /// <summary>
+ /// Initializes a new instance of a <see cref="System.Json.JsonPrimitive"/> type with a <see cref="System.Guid"/> type.
+ /// </summary>
+ /// <param name="value">The <see cref="System.Guid"/> object that initializes the new instance.</param>
+ /// <remarks>A <see cref="System.Json.JsonPrimitive"/> object stores a <see cref="System.Json.JsonType"/> and the value used to initialize it.
+ /// When initialized with a <see cref="System.Guid"/> object, the <see cref="System.Json.JsonType"/> is a <see cref="F:System.Json.JsonType.String"/>, which can be
+ /// recovered using the <see cref="System.Json.JsonPrimitive.JsonType"/> property. The value used to initialize the <see cref="System.Json.JsonPrimitive"/>
+ /// object can be recovered by casting the <see cref="System.Json.JsonPrimitive"/> to <see cref="System.Guid"/>.</remarks>
+ public JsonPrimitive(Guid value)
+ {
+ jsonType = JsonType.String;
+ this.value = value;
+ }
+
+ private JsonPrimitive(object value, JsonType type)
+ {
+ jsonType = type;
+ this.value = value;
+ }
+
+ private enum ReadAsFailureKind
+ {
+ NoFailure,
+ InvalidCast,
+ InvalidDateFormat,
+ InvalidFormat,
+ InvalidUriFormat,
+ Overflow,
+ }
+
+ /// <summary>
+ /// Gets the JsonType that is associated with this <see cref="System.Json.JsonPrimitive"/> object.
+ /// </summary>
+ public override JsonType JsonType
+ {
+ get { return jsonType; }
+ }
+
+ /// <summary>
+ /// Gets the value represented by this instance.
+ /// </summary>
+ [SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods",
+ Justification = "Value in this context clearly refers to the underlying CLR value")]
+ public object Value
+ {
+ get { return value; }
+ }
+
+ /// <summary>
+ /// Attempts to create a <see cref="JsonPrimitive"/> instance from the specified <see cref="object"/> value.
+ /// </summary>
+ /// <param name="value">The <see cref="object"/> value to create the <see cref="JsonPrimitive"/> instance.</param>
+ /// <param name="result">The resulting <see cref="JsonPrimitive"/> instance on success, null otherwise.</param>
+ /// <returns>true if the operation is successful, false otherwise.</returns>
+ public static bool TryCreate(object value, out JsonPrimitive result)
+ {
+ bool allowedType = true;
+ JsonType jsonType = default(JsonType);
+
+ if (value != null)
+ {
+ Type type = value.GetType();
+ switch (Type.GetTypeCode(type))
+ {
+ case TypeCode.Boolean:
+ jsonType = JsonType.Boolean;
+ break;
+ case TypeCode.Byte:
+ case TypeCode.SByte:
+ case TypeCode.Decimal:
+ case TypeCode.Double:
+ case TypeCode.Int16:
+ case TypeCode.Int32:
+ case TypeCode.Int64:
+ case TypeCode.UInt16:
+ case TypeCode.UInt32:
+ case TypeCode.UInt64:
+ case TypeCode.Single:
+ jsonType = JsonType.Number;
+ break;
+ case TypeCode.String:
+ case TypeCode.Char:
+ case TypeCode.DateTime:
+ jsonType = JsonType.String;
+ break;
+ default:
+ if (type == typeof(Uri) || type == typeof(Guid) || type == typeof(DateTimeOffset))
+ {
+ jsonType = JsonType.String;
+ }
+ else
+ {
+ allowedType = false;
+ }
+
+ break;
+ }
+ }
+ else
+ {
+ allowedType = false;
+ }
+
+ if (allowedType)
+ {
+ result = new JsonPrimitive(value, jsonType);
+ return true;
+ }
+ else
+ {
+ result = null;
+ return false;
+ }
+ }
+
+ /// <summary>
+ /// Attempts to convert this <see cref="System.Json.JsonPrimitive"/> instance into an instance of the specified type.
+ /// </summary>
+ /// <param name="type">The type to which the conversion is being performed.</param>
+ /// <returns>An object instance initialized with the <see cref="System.Json.JsonValue"/> value
+ /// specified if the conversion.</returns>
+ /// <exception cref="System.UriFormatException">If T is <see cref="System.Uri"/> and this value does
+ /// not represent a valid Uri.</exception>
+ /// <exception cref="OverflowException">If T is a numeric type, and a narrowing conversion would result
+ /// in a loss of data. For example, if this instance holds an <see cref="System.Int32"/> value of 10000,
+ /// and T is <see cref="System.Byte"/>, this operation would throw an <see cref="System.OverflowException"/>
+ /// because 10000 is outside the range of the <see cref="System.Byte"/> data type.</exception>
+ /// <exception cref="System.FormatException">If the conversion from the string representation of this
+ /// value into another fails because the string is not in the proper format.</exception>
+ /// <exception cref="System.InvalidCastException">If this instance cannot be read as type T.</exception>
+ public override object ReadAs(Type type)
+ {
+ if (type == null)
+ {
+ throw new ArgumentNullException("type");
+ }
+
+ object result;
+ ReadAsFailureKind failure = TryReadAsInternal(type, out result);
+ if (failure == ReadAsFailureKind.NoFailure)
+ {
+ return result;
+ }
+ else
+ {
+ string valueStr = value.ToString();
+ string typeOfTName = type.Name;
+ switch (failure)
+ {
+ case ReadAsFailureKind.InvalidFormat:
+ throw new FormatException(RS.Format(Properties.Resources.CannotReadPrimitiveAsType, valueStr, typeOfTName));
+ case ReadAsFailureKind.InvalidDateFormat:
+ throw new FormatException(RS.Format(Properties.Resources.InvalidDateFormat, valueStr, typeOfTName));
+ case ReadAsFailureKind.InvalidUriFormat:
+ throw new UriFormatException(RS.Format(Properties.Resources.InvalidUriFormat, jsonPrimitiveType.Name, valueStr, typeOfTName, uriType.Name));
+ case ReadAsFailureKind.Overflow:
+ throw new OverflowException(RS.Format(Properties.Resources.OverflowReadAs, valueStr, typeOfTName));
+ case ReadAsFailureKind.InvalidCast:
+ default:
+ throw new InvalidCastException(RS.Format(Properties.Resources.CannotReadPrimitiveAsType, valueStr, typeOfTName));
+ }
+ }
+ }
+
+ /// <summary>
+ /// Attempts to convert this <see cref="System.Json.JsonPrimitive"/> instance into an instance of the specified type.
+ /// </summary>
+ /// <param name="type">The type to which the conversion is being performed.</param>
+ /// <param name="value">An object instance to be initialized with this instance or null if the conversion cannot be performed.</param>
+ /// <returns>true if this <see cref="System.Json.JsonPrimitive"/> instance can be read as the specified type; otherwise, false.</returns>
+ [SuppressMessage("Microsoft.Maintainability", "CA1500:VariableNamesShouldNotMatchFieldNames", MessageId = "value",
+ Justification = "field is used with 'this' and arg is out param which makes it harder to be misused.")]
+ public override bool TryReadAs(Type type, out object value)
+ {
+ return TryReadAsInternal(type, out value) == ReadAsFailureKind.NoFailure;
+ }
+
+ /// <summary>
+ /// Returns the value this object wraps (if any).
+ /// </summary>
+ /// <returns>The value wrapped by this instance or null if none.</returns>
+ internal override object Read()
+ {
+ return value;
+ }
+
+ internal override void Save(XmlDictionaryWriter jsonWriter)
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException("jsonWriter");
+ }
+
+ switch (jsonType)
+ {
+ case JsonType.Boolean:
+ jsonWriter.WriteAttributeString(JXmlToJsonValueConverter.TypeAttributeName, JXmlToJsonValueConverter.BooleanAttributeValue);
+ break;
+ case JsonType.Number:
+ jsonWriter.WriteAttributeString(JXmlToJsonValueConverter.TypeAttributeName, JXmlToJsonValueConverter.NumberAttributeValue);
+ break;
+ default:
+ jsonWriter.WriteAttributeString(JXmlToJsonValueConverter.TypeAttributeName, JXmlToJsonValueConverter.StringAttributeValue);
+ break;
+ }
+
+ WriteValue(jsonWriter);
+ }
+
+ private static ConvertResult StringToBool(string valueString)
+ {
+ ConvertResult result = new ConvertResult();
+ bool tempBool;
+ result.ReadAsFailureKind = Boolean.TryParse(valueString, out tempBool) ? ReadAsFailureKind.NoFailure : ReadAsFailureKind.InvalidFormat;
+ result.Value = tempBool;
+ return result;
+ }
+
+ private static ConvertResult StringToByte(string valueString)
+ {
+ ConvertResult result = new ConvertResult();
+ byte tempByte;
+ result.ReadAsFailureKind = Byte.TryParse(valueString, out tempByte) ? ReadAsFailureKind.NoFailure : ReadAsFailureKind.InvalidCast;
+ if (result.ReadAsFailureKind != ReadAsFailureKind.NoFailure)
+ {
+ result.ReadAsFailureKind = StringToNumberConverter<byte>(valueString, out tempByte);
+ }
+
+ result.Value = tempByte;
+ return result;
+ }
+
+ private static ConvertResult StringToChar(string valueString)
+ {
+ ConvertResult result = new ConvertResult();
+ char tempChar;
+ result.ReadAsFailureKind = Char.TryParse(valueString, out tempChar) ? ReadAsFailureKind.NoFailure : ReadAsFailureKind.InvalidFormat;
+ result.Value = tempChar;
+ return result;
+ }
+
+ private static ConvertResult StringToDecimal(string valueString)
+ {
+ ConvertResult result = new ConvertResult();
+ decimal tempDecimal;
+ result.ReadAsFailureKind = Decimal.TryParse(valueString, NumberStyles.Float, NumberFormatInfo.InvariantInfo, out tempDecimal) ? ReadAsFailureKind.NoFailure : ReadAsFailureKind.InvalidCast;
+ if (result.ReadAsFailureKind != ReadAsFailureKind.NoFailure)
+ {
+ result.ReadAsFailureKind = StringToNumberConverter<decimal>(valueString, out tempDecimal);
+ }
+
+ result.Value = tempDecimal;
+ return result;
+ }
+
+ private static ConvertResult StringToDateTime(string valueString)
+ {
+ ConvertResult result = new ConvertResult();
+ DateTime tempDateTime;
+ result.ReadAsFailureKind = TryParseDateTime(valueString, out tempDateTime) ? ReadAsFailureKind.NoFailure : ReadAsFailureKind.InvalidDateFormat;
+ result.Value = tempDateTime;
+ return result;
+ }
+
+ private static ConvertResult StringToDateTimeOffset(string valueString)
+ {
+ ConvertResult result = new ConvertResult();
+ DateTimeOffset tempDateTimeOffset;
+ result.ReadAsFailureKind = TryParseDateTimeOffset(valueString, out tempDateTimeOffset) ? ReadAsFailureKind.NoFailure : ReadAsFailureKind.InvalidDateFormat;
+ result.Value = tempDateTimeOffset;
+ return result;
+ }
+
+ private static ConvertResult StringToDouble(string valueString)
+ {
+ ConvertResult result = new ConvertResult();
+ double tempDouble;
+ result.ReadAsFailureKind = Double.TryParse(valueString, NumberStyles.Float, NumberFormatInfo.InvariantInfo, out tempDouble) ? ReadAsFailureKind.NoFailure : ReadAsFailureKind.InvalidCast;
+ if (result.ReadAsFailureKind != ReadAsFailureKind.NoFailure)
+ {
+ result.ReadAsFailureKind = StringToNumberConverter<double>(valueString, out tempDouble);
+ }
+
+ result.Value = tempDouble;
+ return result;
+ }
+
+ private static bool TryGuidParse (string value, out Guid guid)
+ {
+#if NET_4_0
+ return Guid.TryParse (value, out guid);
+#else
+ try {
+ guid = new Guid (value);
+ return true;
+ } catch (Exception) {
+ guid = Guid.Empty;
+ return false;
+ }
+#endif
+ }
+
+ private static ConvertResult StringToGuid(string valueString)
+ {
+ ConvertResult result = new ConvertResult();
+ Guid tempGuid;
+ result.ReadAsFailureKind = TryGuidParse(valueString, out tempGuid) ? ReadAsFailureKind.NoFailure : ReadAsFailureKind.InvalidFormat;
+ result.Value = tempGuid;
+ return result;
+ }
+
+ private static ConvertResult StringToShort(string valueString)
+ {
+ ConvertResult result = new ConvertResult();
+ short tempShort;
+ result.ReadAsFailureKind = Int16.TryParse(valueString, NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out tempShort) ? ReadAsFailureKind.NoFailure : ReadAsFailureKind.InvalidCast;
+ if (result.ReadAsFailureKind != ReadAsFailureKind.NoFailure)
+ {
+ result.ReadAsFailureKind = StringToNumberConverter<short>(valueString, out tempShort);
+ }
+
+ result.Value = tempShort;
+ return result;
+ }
+
+ private static ConvertResult StringToInt(string valueString)
+ {
+ ConvertResult result = new ConvertResult();
+ int tempInt;
+ result.ReadAsFailureKind = Int32.TryParse(valueString, NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out tempInt) ? ReadAsFailureKind.NoFailure : ReadAsFailureKind.InvalidCast;
+ if (result.ReadAsFailureKind != ReadAsFailureKind.NoFailure)
+ {
+ result.ReadAsFailureKind = StringToNumberConverter<int>(valueString, out tempInt);
+ }
+
+ result.Value = tempInt;
+ return result;
+ }
+
+ private static ConvertResult StringToLong(string valueString)
+ {
+ ConvertResult result = new ConvertResult();
+ long tempLong;
+ result.ReadAsFailureKind = Int64.TryParse(valueString, NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out tempLong) ? ReadAsFailureKind.NoFailure : ReadAsFailureKind.InvalidCast;
+ if (result.ReadAsFailureKind != ReadAsFailureKind.NoFailure)
+ {
+ result.ReadAsFailureKind = StringToNumberConverter<long>(valueString, out tempLong);
+ }
+
+ result.Value = tempLong;
+ return result;
+ }
+
+ private static ConvertResult StringToSByte(string valueString)
+ {
+ ConvertResult result = new ConvertResult();
+ sbyte tempSByte;
+ result.ReadAsFailureKind = SByte.TryParse(valueString, NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out tempSByte) ? ReadAsFailureKind.NoFailure : ReadAsFailureKind.InvalidCast;
+ if (result.ReadAsFailureKind != ReadAsFailureKind.NoFailure)
+ {
+ result.ReadAsFailureKind = StringToNumberConverter<sbyte>(valueString, out tempSByte);
+ }
+
+ result.Value = tempSByte;
+ return result;
+ }
+
+ private static ConvertResult StringToFloat(string valueString)
+ {
+ ConvertResult result = new ConvertResult();
+ float tempFloat;
+ result.ReadAsFailureKind = Single.TryParse(valueString, NumberStyles.Float, NumberFormatInfo.InvariantInfo, out tempFloat) ? ReadAsFailureKind.NoFailure : ReadAsFailureKind.InvalidCast;
+ if (result.ReadAsFailureKind != ReadAsFailureKind.NoFailure)
+ {
+ result.ReadAsFailureKind = StringToNumberConverter<float>(valueString, out tempFloat);
+ }
+
+ result.Value = tempFloat;
+ return result;
+ }
+
+ private static ConvertResult StringToUShort(string valueString)
+ {
+ ConvertResult result = new ConvertResult();
+ ushort tempUShort;
+ result.ReadAsFailureKind = UInt16.TryParse(valueString, NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out tempUShort) ? ReadAsFailureKind.NoFailure : ReadAsFailureKind.InvalidCast;
+ if (result.ReadAsFailureKind != ReadAsFailureKind.NoFailure)
+ {
+ result.ReadAsFailureKind = StringToNumberConverter<ushort>(valueString, out tempUShort);
+ }
+
+ result.Value = tempUShort;
+ return result;
+ }
+
+ private static ConvertResult StringToUInt(string valueString)
+ {
+ ConvertResult result = new ConvertResult();
+ uint tempUInt;
+ result.ReadAsFailureKind = UInt32.TryParse(valueString, NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out tempUInt) ? ReadAsFailureKind.NoFailure : ReadAsFailureKind.InvalidCast;
+ if (result.ReadAsFailureKind != ReadAsFailureKind.NoFailure)
+ {
+ result.ReadAsFailureKind = StringToNumberConverter<uint>(valueString, out tempUInt);
+ }
+
+ result.Value = tempUInt;
+ return result;
+ }
+
+ private static ConvertResult StringToULong(string valueString)
+ {
+ ConvertResult result = new ConvertResult();
+ ulong tempULong;
+ result.ReadAsFailureKind = UInt64.TryParse(valueString, NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out tempULong) ? ReadAsFailureKind.NoFailure : ReadAsFailureKind.InvalidCast;
+ if (result.ReadAsFailureKind != ReadAsFailureKind.NoFailure)
+ {
+ result.ReadAsFailureKind = StringToNumberConverter<ulong>(valueString, out tempULong);
+ }
+
+ result.Value = tempULong;
+ return result;
+ }
+
+ private static ConvertResult StringToUri(string valueString)
+ {
+ ConvertResult result = new ConvertResult();
+ Uri tempUri;
+ result.ReadAsFailureKind = Uri.TryCreate(valueString, UriKind.RelativeOrAbsolute, out tempUri) ? ReadAsFailureKind.NoFailure : ReadAsFailureKind.InvalidUriFormat;
+ result.Value = tempUri;
+ return result;
+ }
+
+ private static ReadAsFailureKind StringToNumberConverter<T>(string valueString, out T valueNumber)
+ {
+ string str = valueString.Trim();
+
+ if (str.IndexOfAny(FloatingPointChars) < 0)
+ {
+ long longVal;
+ if (Int64.TryParse(str, NumberStyles.Float, CultureInfo.InvariantCulture, out longVal))
+ {
+ return NumberToNumberConverter<T>(longVal, out valueNumber);
+ }
+ }
+
+ decimal decValue;
+ if (Decimal.TryParse(str, NumberStyles.Float, CultureInfo.InvariantCulture, out decValue) && decValue != 0)
+ {
+ return NumberToNumberConverter<T>(decValue, out valueNumber);
+ }
+
+ double dblValue;
+ if (Double.TryParse(str, NumberStyles.Float, CultureInfo.InvariantCulture, out dblValue))
+ {
+ return NumberToNumberConverter<T>(dblValue, out valueNumber);
+ }
+
+ valueNumber = default(T);
+ return ReadAsFailureKind.InvalidFormat;
+ }
+
+ private static ReadAsFailureKind NumberToNumberConverter<T>(object valueObject, out T valueNumber)
+ {
+ object value;
+ ReadAsFailureKind failureKind = NumberToNumberConverter(typeof(T), valueObject, out value);
+ if (failureKind == ReadAsFailureKind.NoFailure)
+ {
+ valueNumber = (T)value;
+ }
+ else
+ {
+ valueNumber = default(T);
+ }
+
+ return failureKind;
+ }
+
+ private static ReadAsFailureKind NumberToNumberConverter(Type type, object valueObject, out object valueNumber)
+ {
+ try
+ {
+ valueNumber = System.Convert.ChangeType(valueObject, type, CultureInfo.InvariantCulture);
+ return ReadAsFailureKind.NoFailure;
+ }
+ catch (OverflowException)
+ {
+ valueNumber = null;
+ return ReadAsFailureKind.Overflow;
+ }
+ }
+
+ private static bool TryParseDateTime(string valueString, out DateTime dateTime)
+ {
+ string filteredValue = valueString.EndsWith(UtcString, StringComparison.Ordinal) ? valueString.Replace(UtcString, GmtString) : valueString;
+
+ if (DateTime.TryParse(filteredValue, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out dateTime))
+ {
+ return true;
+ }
+
+ if (TryParseAspNetDateTimeFormat(valueString, out dateTime))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ private static bool TryParseDateTimeOffset(string valueString, out DateTimeOffset dateTimeOffset)
+ {
+ string filteredValue = valueString.EndsWith(UtcString, StringComparison.Ordinal) ? valueString.Replace(UtcString, GmtString) : valueString;
+
+ if (DateTimeOffset.TryParse(filteredValue, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out dateTimeOffset))
+ {
+ return true;
+ }
+
+ if (TryParseAspNetDateTimeFormat(valueString, out dateTimeOffset))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ private static bool TryParseAspNetDateTimeFormat(string valueString, out DateTime dateTime)
+ {
+ // Reference to the format is available at these sources:
+ // http://msdn.microsoft.com/en-us/library/bb299886.aspx#intro_to_json_sidebarb
+ // http://msdn.microsoft.com/en-us/library/bb412170.aspx
+
+ // The format for the value is given by the following regex:
+ // \/Date\((?<milliseconds>\-?\d+)(?<offset>[\+\-]?\d{4})\)\/
+ // where milliseconds is the number of milliseconds since 1970/01/01:00:00:00.000 UTC (the "unix baseline")
+ // and offset is an optional which indicates whether the value is local or UTC.
+ // The actual value of the offset is ignored, since the ticks represent the UTC offset. The value is converted to local time based on that info.
+ const string DateTimePrefix = "/Date(";
+ const int DateTimePrefixLength = 6;
+ const string DateTimeSuffix = ")/";
+ const int DateTimeSuffixLength = 2;
+
+ if (valueString.StartsWith(DateTimePrefix, StringComparison.Ordinal) && valueString.EndsWith(DateTimeSuffix, StringComparison.Ordinal))
+ {
+ string ticksValue = valueString.Substring(DateTimePrefixLength, valueString.Length - DateTimePrefixLength - DateTimeSuffixLength);
+ DateTimeKind dateTimeKind = DateTimeKind.Utc;
+
+ int indexOfTimeZoneOffset = ticksValue.IndexOf('+', 1);
+
+ if (indexOfTimeZoneOffset < 0)
+ {
+ indexOfTimeZoneOffset = ticksValue.IndexOf('-', 1);
+ }
+
+ // If an offset is present, verify it is properly formatted. Actual value is ignored (see spec).
+ if (indexOfTimeZoneOffset != -1)
+ {
+ if (indexOfTimeZoneOffset + 5 == ticksValue.Length
+ && IsLatinDigit(ticksValue[indexOfTimeZoneOffset + 1])
+ && IsLatinDigit(ticksValue[indexOfTimeZoneOffset + 2])
+ && IsLatinDigit(ticksValue[indexOfTimeZoneOffset + 3])
+ && IsLatinDigit(ticksValue[indexOfTimeZoneOffset + 4]))
+ {
+ ticksValue = ticksValue.Substring(0, indexOfTimeZoneOffset);
+ dateTimeKind = DateTimeKind.Local;
+ }
+ else
+ {
+ dateTime = new DateTime();
+ return false;
+ }
+ }
+
+ long millisecondsSinceUnixEpoch;
+ if (Int64.TryParse(ticksValue, NumberStyles.Integer, CultureInfo.InvariantCulture, out millisecondsSinceUnixEpoch))
+ {
+ long ticks = (millisecondsSinceUnixEpoch * 10000) + UnixEpochTicks;
+ if (ticks < DateTime.MaxValue.Ticks)
+ {
+ dateTime = new DateTime(ticks, DateTimeKind.Utc);
+ if (dateTimeKind == DateTimeKind.Local)
+ {
+ dateTime = dateTime.ToLocalTime();
+ }
+
+ return true;
+ }
+ }
+ }
+
+ dateTime = new DateTime();
+ return false;
+ }
+
+ private static bool TryParseAspNetDateTimeFormat(string valueString, out DateTimeOffset dateTimeOffset)
+ {
+ DateTime dateTime;
+ if (TryParseAspNetDateTimeFormat(valueString, out dateTime))
+ {
+ dateTimeOffset = new DateTimeOffset(dateTime);
+ return true;
+ }
+
+ dateTimeOffset = new DateTimeOffset();
+ return false;
+ }
+
+ private static bool IsLatinDigit(char c)
+ {
+ return (c >= '0') && (c <= '9');
+ }
+
+ private static string UnescapeJsonString(string val)
+ {
+ if (val == null)
+ {
+ return null;
+ }
+
+ StringBuilder sb = null;
+ int startIndex = 0, count = 0;
+ for (int i = 0; i < val.Length; i++)
+ {
+ if (val[i] == '\\')
+ {
+ i++;
+ if (sb == null)
+ {
+ sb = new StringBuilder();
+ }
+
+ sb.Append(val, startIndex, count);
+#if NET_4_0
+ Contract.Assert(i < val.Length, "Found that a '\' was the last character in a string, which is invalid JSON. Verify the calling method uses a valid JSON string as the input parameter of this method.");
+#endif
+ switch (val[i])
+ {
+ case '"':
+ case '\'':
+ case '/':
+ case '\\':
+ sb.Append(val[i]);
+ break;
+ case 'b':
+ sb.Append('\b');
+ break;
+ case 'f':
+ sb.Append('\f');
+ break;
+ case 'n':
+ sb.Append('\n');
+ break;
+ case 'r':
+ sb.Append('\r');
+ break;
+ case 't':
+ sb.Append('\t');
+ break;
+ case 'u':
+#if NET_4_0
+ Contract.Assert((i + 3) < val.Length, String.Format(CultureInfo.CurrentCulture, "Unexpected char {0} at position {1}. The unicode escape sequence should be followed by 4 digits.", val[i], i));
+#endif
+ sb.Append(ParseChar(val.Substring(i + 1, 4), NumberStyles.HexNumber));
+ i += 4;
+ break;
+ }
+
+ startIndex = i + 1;
+ count = 0;
+ }
+ else
+ {
+ count++;
+ }
+ }
+
+ if (sb == null)
+ {
+ return val;
+ }
+
+ if (count > 0)
+ {
+ sb.Append(val, startIndex, count);
+ }
+
+ return sb.ToString();
+ }
+
+ private static char ParseChar(string value, NumberStyles style)
+ {
+ try
+ {
+ int intValue = Int32.Parse(value, style, NumberFormatInfo.InvariantInfo);
+ return System.Convert.ToChar(intValue);
+ }
+ catch (ArgumentException exception)
+ {
+ throw new InvalidCastException(exception.Message, exception);
+ }
+ catch (FormatException exception)
+ {
+ throw new InvalidCastException(exception.Message, exception);
+ }
+ catch (OverflowException exception)
+ {
+ throw new InvalidCastException(exception.Message, exception);
+ }
+ }
+
+ [SuppressMessage("Microsoft.Maintainability", "CA1500:VariableNamesShouldNotMatchFieldNames", MessageId = "value",
+ Justification = "field is used with 'this' and arg is out param which makes it harder to be misused.")]
+ private ReadAsFailureKind TryReadAsInternal(Type type, out object value)
+ {
+ if (base.TryReadAs(type, out value))
+ {
+ return ReadAsFailureKind.NoFailure;
+ }
+
+ if (type == this.value.GetType())
+ {
+ value = this.value;
+ return ReadAsFailureKind.NoFailure;
+ }
+
+ if (jsonType == JsonType.Number)
+ {
+ switch (Type.GetTypeCode(type))
+ {
+ case TypeCode.Byte:
+ case TypeCode.SByte:
+ case TypeCode.Int16:
+ case TypeCode.Int32:
+ case TypeCode.Int64:
+ case TypeCode.UInt16:
+ case TypeCode.UInt32:
+ case TypeCode.UInt64:
+ case TypeCode.Single:
+ case TypeCode.Double:
+ case TypeCode.Decimal:
+ return NumberToNumberConverter(type, this.value, out value);
+ case TypeCode.String:
+ value = ToString();
+ return ReadAsFailureKind.NoFailure;
+ }
+ }
+
+ if (jsonType == JsonType.Boolean)
+ {
+ if (type == typeof(string))
+ {
+ value = ToString();
+ return ReadAsFailureKind.NoFailure;
+ }
+ }
+
+ if (jsonType == JsonType.String)
+ {
+ string str = UnescapeJsonString(ToString());
+#if NET_4_0
+ Contract.Assert(str.Length >= 2 && str.StartsWith("\"", StringComparison.Ordinal) && str.EndsWith("\"", StringComparison.Ordinal), "The unescaped string must begin and end with quotes.");
+#endif
+ str = str.Substring(1, str.Length - 2);
+
+ if (stringConverters.ContainsKey(type))
+ {
+ ConvertResult result = stringConverters[type].Invoke(str);
+ value = result.Value;
+ return result.ReadAsFailureKind;
+ }
+
+ if (type == typeof(string))
+ {
+ value = str;
+ return ReadAsFailureKind.NoFailure;
+ }
+ }
+
+ value = null;
+ return ReadAsFailureKind.InvalidCast;
+ }
+
+ private void WriteValue(XmlDictionaryWriter jsonWriter)
+ {
+ Type valueType = value.GetType();
+ switch (Type.GetTypeCode(valueType))
+ {
+ case TypeCode.Boolean:
+ jsonWriter.WriteValue((bool)value);
+ break;
+ case TypeCode.Byte:
+ case TypeCode.Int16:
+ case TypeCode.Int32:
+ case TypeCode.Int64:
+ case TypeCode.SByte:
+ case TypeCode.UInt16:
+ case TypeCode.UInt32:
+ case TypeCode.UInt64:
+ case TypeCode.Decimal:
+ jsonWriter.WriteValue(String.Format(CultureInfo.InvariantCulture, "{0}", value));
+ break;
+ case TypeCode.Single:
+ case TypeCode.Double:
+ jsonWriter.WriteValue(String.Format(CultureInfo.InvariantCulture, "{0:R}", value));
+ break;
+ case TypeCode.Char:
+ jsonWriter.WriteValue(new string((char)value, 1));
+ break;
+ case TypeCode.String:
+ jsonWriter.WriteValue((string)value);
+ break;
+ case TypeCode.DateTime:
+ jsonWriter.WriteValue(((DateTime)value).ToString(DateTimeIsoFormat, CultureInfo.InvariantCulture));
+ break;
+ default:
+ if (valueType == typeof(Uri))
+ {
+ Uri uri = (Uri)value;
+ jsonWriter.WriteValue(uri.GetComponents(UriComponents.SerializationInfoString, UriFormat.UriEscaped));
+ }
+ else if (valueType == typeof(DateTimeOffset))
+ {
+ jsonWriter.WriteValue(((DateTimeOffset)value).ToString(DateTimeIsoFormat, CultureInfo.InvariantCulture));
+ }
+ else
+ {
+ jsonWriter.WriteValue(value);
+ }
+
+ break;
+ }
+ }
+
+ private class ConvertResult
+ {
+ public ReadAsFailureKind ReadAsFailureKind { get; set; }
+
+ public object Value { get; set; }
+ }
+ }
+}
diff --git a/mcs/class/System.Json.Microsoft/System.Json/JsonType.cs b/mcs/class/System.Json.Microsoft/System.Json/JsonType.cs
new file mode 100644
index 00000000000..785026c32d7
--- /dev/null
+++ b/mcs/class/System.Json.Microsoft/System.Json/JsonType.cs
@@ -0,0 +1,50 @@
+// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
+
+namespace System.Json
+{
+ /// <summary>
+ /// An enumeration that specifies primitive and structured JavaScript Object
+ /// Notation (JSON) common language runtime (CLR) types.
+ /// </summary>
+ public enum JsonType
+ {
+ /// <summary>
+ /// Specifies the JSON string CLR type.
+ /// </summary>
+ String,
+
+ /// <summary>
+ /// Specifies the JSON number CLR type.
+ /// </summary>
+ Number,
+
+ /// <summary>
+ /// Specifies the JSON object CLR type that consists of an unordered collection
+ /// of key/value pairs, where the key is of type String and the value is of
+ /// type <see cref="System.Json.JsonValue"/>, which can, in turn, be either a
+ /// primitive or a structured JSON type.
+ /// </summary>
+ Object,
+
+ /// <summary>
+ /// Specifies the JSON array CLR type that consists of an ordered collection of
+ /// <see cref="System.Json.JsonValue"/>types, which can, in turn, be either
+ /// primitive or structured JSON types.
+ /// </summary>
+ Array,
+
+ /// <summary>
+ /// Specifies the JSON Boolean CLR type.
+ /// </summary>
+ Boolean,
+
+ /// <summary>
+ /// Specifies the type returned by calls to <see cref="System.Json.JsonValue.ValueOrDefault(string)"/>
+ /// or <see cref="System.Json.JsonValue.ValueOrDefault(int)"/>
+ /// when the element searches doesn't exist in the JSON collection. This is a special
+ /// value which does not represent any JSON element, and cannot be added to any
+ /// JSON collections.
+ /// </summary>
+ Default
+ }
+}
diff --git a/mcs/class/System.Json.Microsoft/System.Json/JsonValue.cs b/mcs/class/System.Json.Microsoft/System.Json/JsonValue.cs
new file mode 100644
index 00000000000..97dbae5517e
--- /dev/null
+++ b/mcs/class/System.Json.Microsoft/System.Json/JsonValue.cs
@@ -0,0 +1,1249 @@
+// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
+
+using System.Collections;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Diagnostics.CodeAnalysis;
+#if FEATURE_DYNAMIC
+using System.Dynamic;
+#endif
+using System.Globalization;
+using System.IO;
+using System.Linq.Expressions;
+using System.Runtime.Serialization;
+using System.Runtime.Serialization.Json;
+using System.Text;
+using System.Xml;
+
+namespace System.Json
+{
+ /// <summary>
+ /// This is the base class for JavaScript Object Notation (JSON) common language runtime (CLR) types.
+ /// </summary>
+ [SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix",
+ Justification = "JsonValue is by definition either a collection or a single object.")]
+ [DataContract]
+#if FEATURE_DYNAMIC
+ public class JsonValue : IEnumerable<KeyValuePair<string, JsonValue>>, IDynamicMetaObjectProvider
+#else
+ public class JsonValue : IEnumerable<KeyValuePair<string, JsonValue>>
+#endif
+ {
+ private static JsonValue defaultInstance = new JsonValue();
+ private int changingListenersCount;
+ private int changedListenersCount;
+
+ internal JsonValue()
+ {
+ }
+
+ /// <summary>
+ /// Raised when this <see cref="System.Json.JsonValue"/> or any of its members have changed.
+ /// </summary>
+ /// <remarks><p>Events are raised when elements are added or removed to <see cref="System.Json.JsonValue"/>
+ /// instances. It applies to both complex descendants of <see cref="System.Json.JsonValue"/>: <see cref="System.Json.JsonArray"/>
+ /// and <see cref="System.Json.JsonObject"/>.</p>
+ /// <p>You should be careful when modifying a <see cref="System.Json.JsonValue"/> tree within one of these events,
+ /// because doing this might lead to unexpected results. For example, if you receive a Changing event, and while
+ /// the event is being processed you remove the node from the tree, you might not receive the Changed event. When
+ /// an event is being processed, it is valid to modify a tree other than the one that contains the node that is
+ /// receiving the event; it is even valid to modify the same tree provided the modifications do not affect the
+ /// specific nodes on which the event was raised. However, if you modify the area of the tree that contains the
+ /// node receiving the event, the events that you receive and the impact to the tree are undefined.</p></remarks>
+ public event EventHandler<JsonValueChangeEventArgs> Changed
+ {
+ add
+ {
+ changedListenersCount++;
+ OnChanged += value;
+ }
+
+ remove
+ {
+ changedListenersCount--;
+ OnChanged -= value;
+ }
+ }
+
+ /// <summary>
+ /// Raised when this <see cref="System.Json.JsonValue"/> or any of its members are about to be changed.
+ /// </summary>
+ /// <remarks><p>Events are raised when elements are added or removed to <see cref="System.Json.JsonValue"/>
+ /// instances. It applies to both complex descendants of <see cref="System.Json.JsonValue"/>: <see cref="System.Json.JsonArray"/>
+ /// and <see cref="System.Json.JsonObject"/>.</p>
+ /// <p>You should be careful when modifying a <see cref="System.Json.JsonValue"/> tree within one of these events,
+ /// because doing this might lead to unexpected results. For example, if you receive a Changing event, and while
+ /// the event is being processed you remove the node from the tree, you might not receive the Changed event. When
+ /// an event is being processed, it is valid to modify a tree other than the one that contains the node that is
+ /// receiving the event; it is even valid to modify the same tree provided the modifications do not affect the
+ /// specific nodes on which the event was raised. However, if you modify the area of the tree that contains the
+ /// node receiving the event, the events that you receive and the impact to the tree are undefined.</p></remarks>
+ public event EventHandler<JsonValueChangeEventArgs> Changing
+ {
+ add
+ {
+ changingListenersCount++;
+ OnChanging += value;
+ }
+
+ remove
+ {
+ changingListenersCount--;
+ OnChanging -= value;
+ }
+ }
+
+ private event EventHandler<JsonValueChangeEventArgs> OnChanged;
+ private event EventHandler<JsonValueChangeEventArgs> OnChanging;
+
+ /// <summary>
+ /// Gets the JSON CLR type represented by this instance.
+ /// </summary>
+ public virtual JsonType JsonType
+ {
+ get { return JsonType.Default; }
+ }
+
+ /// <summary>
+ /// Gets the number of items in this object.
+ /// </summary>
+ public virtual int Count
+ {
+ get { return 0; }
+ }
+
+ /// <summary>
+ /// Gets the number of listeners to the <see cref="Changing"/> event for this instance.
+ /// </summary>
+ protected int ChangingListenersCount
+ {
+ get { return changingListenersCount; }
+ }
+
+ /// <summary>
+ /// Gets the number of listeners to the <see cref="Changed"/> event for this instance.
+ /// </summary>
+ protected int ChangedListenersCount
+ {
+ get { return changedListenersCount; }
+ }
+
+ /// <summary>
+ /// Gets the default JsonValue instance.
+ /// This instance enables safe-chaining of JsonValue operations and resolves to 'null'
+ /// when this instance is used as dynamic, mapping to the JavaScript 'null' value.
+ /// </summary>
+ private static JsonValue DefaultInstance
+ {
+ get { return defaultInstance; }
+ }
+
+ /// <summary>
+ /// This indexer is not supported for this base class and throws an exception.
+ /// </summary>
+ /// <param name="key">The key of the element to get or set.</param>
+ /// <returns><see cref="System.Json.JsonValue"/>.</returns>
+ /// <remarks>The exception thrown is the <see cref="System.InvalidOperationException"/>.
+ /// This method is overloaded in the implementation of the <see cref="System.Json.JsonObject"/>
+ /// class, which inherits from this class.</remarks>
+ public virtual JsonValue this[string key]
+ {
+ get { throw new InvalidOperationException(RS.Format(Properties.Resources.IndexerNotSupportedOnJsonType, typeof(string), JsonType)); }
+
+ set { throw new InvalidOperationException(RS.Format(Properties.Resources.IndexerNotSupportedOnJsonType, typeof(string), JsonType)); }
+ }
+
+ /// <summary>
+ /// This indexer is not supported for this base class and throws an exception.
+ /// </summary>
+ /// <param name="index">The zero-based index of the element to get or set.</param>
+ /// <returns><see cref="System.Json.JsonValue"/>.</returns>
+ /// <remarks>The exception thrown is the <see cref="System.InvalidOperationException"/>.
+ /// This method is overloaded in the implementation of the <see cref="System.Json.JsonArray"/>
+ /// class, which inherits from this class.</remarks>
+ public virtual JsonValue this[int index]
+ {
+ get { throw new InvalidOperationException(RS.Format(Properties.Resources.IndexerNotSupportedOnJsonType, typeof(int), JsonType)); }
+
+ set { throw new InvalidOperationException(RS.Format(Properties.Resources.IndexerNotSupportedOnJsonType, typeof(int), JsonType)); }
+ }
+
+ /// <summary>
+ /// Deserializes text-based JSON into a JSON CLR type.
+ /// </summary>
+ /// <param name="json">The text-based JSON to be parsed into a JSON CLR type.</param>
+ /// <returns>The <see cref="System.Json.JsonValue"/> object that represents the parsed
+ /// text-based JSON as a CLR type.</returns>
+ /// <exception cref="System.ArgumentException">The length of jsonString is zero.</exception>
+ /// <exception cref="System.ArgumentNullException">jsonString is null.</exception>
+ /// <remarks>The result will be an instance of either <see cref="System.Json.JsonArray"/>,
+ /// <see cref="System.Json.JsonObject"/> or <see cref="System.Json.JsonPrimitive"/>,
+ /// depending on the text-based JSON supplied to the method.</remarks>
+ public static JsonValue Parse(string json)
+ {
+ return JXmlToJsonValueConverter.JXMLToJsonValue(json);
+ }
+
+ /// <summary>
+ /// Deserializes text-based JSON from a text reader into a JSON CLR type.
+ /// </summary>
+ /// <param name="textReader">A <see cref="System.IO.TextReader"/> over text-based JSON content.</param>
+ /// <returns>The <see cref="System.Json.JsonValue"/> object that represents the parsed
+ /// text-based JSON as a CLR type.</returns>
+ /// <exception cref="System.ArgumentNullException">textReader is null.</exception>
+ /// <remarks>The result will be an instance of either <see cref="System.Json.JsonArray"/>,
+ /// <see cref="System.Json.JsonObject"/> or <see cref="System.Json.JsonPrimitive"/>,
+ /// depending on the text-based JSON supplied to the method.</remarks>
+ public static JsonValue Load(TextReader textReader)
+ {
+ if (textReader == null)
+ {
+ throw new ArgumentNullException("textReader");
+ }
+
+ return JsonValue.Parse(textReader.ReadToEnd());
+ }
+
+ /// <summary>
+ /// Deserializes text-based JSON from a stream into a JSON CLR type.
+ /// </summary>
+ /// <param name="stream">A <see cref="System.IO.Stream"/> that contains text-based JSON content.</param>
+ /// <returns>The <see cref="System.Json.JsonValue"/> object that represents the parsed
+ /// text-based JSON as a CLR type.</returns>
+ /// <exception cref="System.ArgumentNullException">stream is null.</exception>
+ /// <remarks>The result will be an instance of either <see cref="System.Json.JsonArray"/>,
+ /// <see cref="System.Json.JsonObject"/> or <see cref="System.Json.JsonPrimitive"/>,
+ /// depending on the text-based JSON supplied to the method.</remarks>
+ public static JsonValue Load(Stream stream)
+ {
+ return JXmlToJsonValueConverter.JXMLToJsonValue(stream);
+ }
+
+ /// <summary>
+ /// Performs a cast operation from a <see cref="JsonValue"/> instance into the specified type parameter./>
+ /// </summary>
+ /// <typeparam name="T">The type to cast the instance to.</typeparam>
+ /// <param name="value">The <see cref="System.Json.JsonValue"/> instance.</param>
+ /// <returns>An object of type T initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
+ /// <remarks>This method is to support the framework and is not intended to be used externally, use explicit type cast instead.</remarks>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter",
+ Justification = "The generic parameter is used to specify the output type")]
+ public static T CastValue<T>(JsonValue value)
+ {
+ Type typeofT = typeof(T);
+
+ if ((value != null && typeofT.IsAssignableFrom(value.GetType())) || typeofT == typeof(object))
+ {
+ return (T)(object)value;
+ }
+
+ if (value == null || value.JsonType == JsonType.Default)
+ {
+ if (typeofT.IsValueType)
+ {
+ throw new InvalidCastException(RS.Format(Properties.Resources.InvalidCastNonNullable, typeofT.FullName));
+ }
+ else
+ {
+ return default(T);
+ }
+ }
+
+ try
+ {
+ return value.ReadAs<T>();
+ }
+ catch (Exception ex)
+ {
+ if (ex is FormatException || ex is NotSupportedException || ex is InvalidCastException)
+ {
+ throw new InvalidCastException(RS.Format(Properties.Resources.CannotCastJsonValue, value.GetType().FullName, typeofT.FullName), ex);
+ }
+
+ throw;
+ }
+ }
+
+ /// <summary>
+ /// Returns an enumerator which iterates through the values in this object.
+ /// </summary>
+ /// <returns>An enumerator which which iterates through the values in this object.</returns>
+ /// <remarks>The enumerator returned by this class is empty; subclasses will override this method to return appropriate enumerators for themselves.</remarks>
+ public IEnumerator<KeyValuePair<string, JsonValue>> GetEnumerator()
+ {
+ return GetKeyValuePairEnumerator();
+ }
+
+ /// <summary>
+ /// Returns an enumerator which iterates through the values in this object.
+ /// </summary>
+ /// <returns>An <see cref="System.Collections.IEnumerator"/> which iterates through the values in this object.</returns>
+ /// <remarks>The enumerator returned by this class is empty; subclasses will override this method to return appropriate enumerators for themselves.</remarks>
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetKeyValuePairEnumerator();
+ }
+
+#if FEATURE_DYNAMIC
+ /// <summary>
+ /// Gets this instance as a <code>dynamic</code> object.
+ /// </summary>
+ /// <returns>This instance as <code>dynamic</code>.</returns>
+ public dynamic AsDynamic()
+ {
+ return this;
+ }
+#endif
+
+ /// <summary>
+ /// Attempts to convert this <see cref="System.Json.JsonValue"/> instance into the type T.
+ /// </summary>
+ /// <typeparam name="T">The type to which the conversion is being performed.</typeparam>
+ /// <param name="valueOfT">An instance of T initialized with this instance, or the default value of T if the conversion cannot be performed.</param>
+ /// <returns>true if this <see cref="System.Json.JsonValue"/> instance can be read as type T; otherwise, false.</returns>
+ public bool TryReadAs<T>(out T valueOfT)
+ {
+ object value;
+ if (TryReadAs(typeof(T), out value))
+ {
+ valueOfT = (T)value;
+ return true;
+ }
+
+ valueOfT = default(T);
+ return false;
+ }
+
+ /// <summary>
+ /// Attempts to convert this <see cref="System.Json.JsonValue"/> instance into the type T.
+ /// </summary>
+ /// <typeparam name="T">The type to which the conversion is being performed.</typeparam>
+ /// <returns>An instance of T initialized with the value from the conversion of this instance.</returns>
+ /// <exception cref="System.NotSupportedException">If this <see cref="System.Json.JsonValue"/> value cannot be converted into the type T.</exception>
+ [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter",
+ Justification = "The generic parameter is used to specify the output type")]
+ public T ReadAs<T>()
+ {
+ return (T)ReadAs(typeof(T));
+ }
+
+ /// <summary>
+ /// Attempts to convert this <see cref="System.Json.JsonValue"/> instance into the type T.
+ /// </summary>
+ /// <typeparam name="T">The type to which the conversion is being performed.</typeparam>
+ /// <param name="fallback">The fallback value to be returned if the conversion cannot be made.</param>
+ /// <returns>An instance of T initialized with the value from the conversion of this instance, or the specified fallback value if the conversion cannot be made.</returns>
+ public T ReadAs<T>(T fallback)
+ {
+ return (T)ReadAs(typeof(T), fallback);
+ }
+
+ /// <summary>
+ /// Attempts to convert this <see cref="System.Json.JsonValue"/> instance to an instance of the specified type.
+ /// </summary>
+ /// <param name="type">The type to which the conversion is being performed.</param>
+ /// <param name="fallback">The fallback value to be returned if the conversion cannot be made.</param>
+ /// <returns>An instance of the specified type initialized with the value from the conversion of this instance, or the specified fallback value if the conversion cannot be made.</returns>
+ public object ReadAs(Type type, object fallback)
+ {
+ if (type == null)
+ {
+ throw new ArgumentNullException("type");
+ }
+
+ object result;
+ if (JsonType != JsonType.Default && TryReadAs(type, out result))
+ {
+ return result;
+ }
+ else
+ {
+ return fallback;
+ }
+ }
+
+ /// <summary>
+ /// Attempts to convert this <see cref="System.Json.JsonValue"/> instance into an instance of the specified type.
+ /// </summary>
+ /// <param name="type">The type to which the conversion is being performed.</param>
+ /// <returns>An instance of the specified type initialized with the value from the conversion of this instance.</returns>
+ /// <exception cref="System.NotSupportedException">If this <see cref="System.Json.JsonValue"/> value cannot be converted into the type T.</exception>
+ public virtual object ReadAs(Type type)
+ {
+ if (type == null)
+ {
+ throw new ArgumentNullException("type");
+ }
+
+ object result;
+ if (TryReadAs(type, out result))
+ {
+ return result;
+ }
+
+ throw new NotSupportedException(RS.Format(Properties.Resources.CannotReadAsType, GetType().FullName, type.FullName));
+ }
+
+ /// <summary>
+ /// Attempts to convert this <see cref="System.Json.JsonValue"/> instance into an instance of the specified type.
+ /// </summary>
+ /// <param name="type">The type to which the conversion is being performed.</param>
+ /// <param name="value">An object to be initialized with this instance or null if the conversion cannot be performed.</param>
+ /// <returns>true if this <see cref="System.Json.JsonValue"/> instance can be read as the specified type; otherwise, false.</returns>
+ [SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate",
+ Justification = "This is the non-generic version of the method.")]
+ public virtual bool TryReadAs(Type type, out object value)
+ {
+ if (type == null)
+ {
+ throw new ArgumentNullException("type");
+ }
+
+ if (type.IsAssignableFrom(GetType()) || type == typeof(object))
+ {
+ value = this;
+ return true;
+ }
+
+ value = null;
+ return false;
+ }
+
+ /// <summary>
+ /// Writes this <see cref="System.Json.JsonValue"/> instance to a <see cref="System.IO.Stream"/>.
+ /// </summary>
+ /// <param name="stream">Stream to which to write text-based JSON.</param>
+ public void Save(Stream stream)
+ {
+ if (JsonType == JsonType.Default)
+ {
+ throw new InvalidOperationException(Properties.Resources.UseOfDefaultNotAllowed);
+ }
+
+ if (stream == null)
+ {
+ throw new ArgumentNullException("stream");
+ }
+
+ using (XmlDictionaryWriter jsonWriter = JsonReaderWriterFactory.CreateJsonWriter(stream, Encoding.UTF8, false))
+ {
+ jsonWriter.WriteStartElement(JXmlToJsonValueConverter.RootElementName);
+ Save(jsonWriter);
+ jsonWriter.WriteEndElement();
+ }
+ }
+
+ /// <summary>
+ /// Writes <see cref="System.Json.JsonValue"/> instance to a <see cref="TextWriter"/>.
+ /// </summary>
+ /// <param name="textWriter">The <see cref="System.IO.TextWriter"/> used to write text-based JSON.</param>
+ public void Save(TextWriter textWriter)
+ {
+ if (JsonType == JsonType.Default)
+ {
+ throw new InvalidOperationException(Properties.Resources.UseOfDefaultNotAllowed);
+ }
+
+ if (textWriter == null)
+ {
+ throw new ArgumentNullException("textWriter");
+ }
+
+ using (MemoryStream ms = new MemoryStream())
+ {
+ Save(ms);
+ ms.Position = 0;
+ textWriter.Write(new StreamReader(ms).ReadToEnd());
+ }
+ }
+
+ /// <summary>
+ /// Provides a textual representation of this <see cref="System.Json.JsonValue"/> instance.
+ /// </summary>
+ /// <returns>A <see cref="System.String"/> containing text-based JSON.</returns>
+ public override string ToString()
+ {
+ if (JsonType == JsonType.Default)
+ {
+ return "Default";
+ }
+
+ using (MemoryStream ms = new MemoryStream())
+ {
+ Save(ms);
+ ms.Position = 0;
+ return new StreamReader(ms).ReadToEnd();
+ }
+ }
+
+ /// <summary>
+ /// Checks whether a key/value pair with a specified key exists in the JSON CLR object type.
+ /// </summary>
+ /// <param name="key">The key to check for.</param>
+ /// <returns>false in this class; subclasses may override this method to return other values.</returns>
+ /// <remarks>This method is overloaded in the implementation of the <see cref="System.Json.JsonObject"/>
+ /// class, which inherits from this class.</remarks>
+ public virtual bool ContainsKey(string key)
+ {
+ return false;
+ }
+
+ /// <summary>
+ /// Returns the value returned by the safe string indexer for this instance.
+ /// </summary>
+ /// <param name="key">The key of the element to get.</param>
+ /// <returns>If this is an instance of <see cref="System.Json.JsonObject"/>, it contains
+ /// the given key and the value corresponding to the key 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>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public virtual JsonValue GetValue(string key)
+ {
+ return ValueOrDefault(key);
+ }
+
+ /// <summary>
+ /// Returns the value returned by the safe int indexer for this instance.
+ /// </summary>
+ /// <param name="index">The zero-based index of the element to get.</param>
+ /// <returns>If this is an instance of <see cref="System.Json.JsonArray"/>, 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>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public virtual JsonValue GetValue(int index)
+ {
+ return ValueOrDefault(index);
+ }
+
+ /// <summary>
+ /// Sets the value and returns it.
+ /// </summary>
+ /// <param name="key">The key of the element to set.</param>
+ /// <param name="value">The value to be set.</param>
+ /// <returns>The value, converted into a JsonValue, set in this collection.</returns>
+ /// <exception cref="System.ArgumentException">If the value cannot be converted into a JsonValue.</exception>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public virtual JsonValue SetValue(string key, object value)
+ {
+ this[key] = ResolveObject(value);
+ return this[key];
+ }
+
+ /// <summary>
+ /// Sets the value and returns it.
+ /// </summary>
+ /// <param name="index">The zero-based index of the element to set.</param>
+ /// <param name="value">The value to be set.</param>
+ /// <returns>The value, converted into a JsonValue, set in this collection.</returns>
+ /// <exception cref="System.ArgumentException">If the value cannot be converted into a JsonValue.</exception>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public virtual JsonValue SetValue(int index, object value)
+ {
+ this[index] = ResolveObject(value);
+ return this[index];
+ }
+
+ /// <summary>
+ /// Safe string indexer for the <see cref="System.Json.JsonValue"/> type.
+ /// </summary>
+ /// <param name="key">The key of the element to get.</param>
+ /// <returns>If this is an instance of <see cref="System.Json.JsonObject"/>, it contains
+ /// the given key and the value corresponding to the key 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 virtual JsonValue ValueOrDefault(string key)
+ {
+ return JsonValue.DefaultInstance;
+ }
+
+ /// <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 this is an instance of <see cref="System.Json.JsonArray"/>, 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 virtual JsonValue ValueOrDefault(int index)
+ {
+ return JsonValue.DefaultInstance;
+ }
+
+ /// <summary>
+ /// Safe deep indexer for the <see cref="JsonValue"/> type.
+ /// </summary>
+ /// <param name="indexes">The indices to index this type. The indices can be
+ /// of type <see cref="System.Int32"/> or <see cref="System.String"/>.</param>
+ /// <returns>A <see cref="JsonValue"/> which is equivalent to calling<see cref="ValueOrDefault(int)"/> or
+ /// <see cref="ValueOrDefault(string)"/> on the first index, then calling it again on the result
+ /// for the second index and so on.</returns>
+ /// <exception cref="System.ArgumentException">If any of the indices is not of type
+ /// <see cref="System.Int32"/> or <see cref="System.String"/>.</exception>
+ public JsonValue ValueOrDefault(params object[] indexes)
+ {
+ if (indexes == null)
+ {
+ return JsonValue.DefaultInstance;
+ }
+
+ if (indexes.Length == 0)
+ {
+ return this;
+ }
+
+ JsonValue result = this;
+ for (int i = 0; i < indexes.Length; i++)
+ {
+ object index = indexes[i];
+ if (index == null)
+ {
+ result = JsonValue.DefaultInstance;
+ continue;
+ }
+
+ Type indexType = index.GetType();
+
+ switch (Type.GetTypeCode(indexType))
+ {
+ case TypeCode.Char:
+ case TypeCode.Int16:
+ case TypeCode.UInt16:
+ case TypeCode.Byte:
+ case TypeCode.SByte:
+ index = System.Convert.ChangeType(index, typeof(int), CultureInfo.InvariantCulture);
+ goto case TypeCode.Int32;
+
+ case TypeCode.Int32:
+ result = result.ValueOrDefault((int)index);
+ break;
+
+ case TypeCode.String:
+ result = result.ValueOrDefault((string)index);
+ break;
+
+ default:
+ throw new ArgumentException(RS.Format(Properties.Resources.InvalidIndexType, index.GetType()), "indexes");
+ }
+ }
+
+ return result;
+ }
+
+#if FEATURE_DYNAMIC
+ [SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes",
+ Justification = "Cannot make this class sealed, it needs to have subclasses. But its subclasses are sealed themselves.")]
+ DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression parameter)
+ {
+ if (parameter == null)
+ {
+ throw new ArgumentNullException("parameter");
+ }
+
+ return new JsonValueDynamicMetaObject(parameter, this);
+ }
+#endif
+
+ /// <summary>
+ /// Resolves the specified object to an appropriate JsonValue instance.
+ /// </summary>
+ /// <param name="value">The object to resolve.</param>
+ /// <returns>A <see cref="JsonValue"/> instance resolved from the specified object.</returns>
+ internal static JsonValue ResolveObject(object value)
+ {
+ JsonPrimitive primitive;
+
+ if (value == null)
+ {
+ return null;
+ }
+
+ JsonValue jsonValue = value as JsonValue;
+
+ if (jsonValue != null)
+ {
+ return jsonValue;
+ }
+
+ if (JsonPrimitive.TryCreate(value, out primitive))
+ {
+ return primitive;
+ }
+
+ throw new ArgumentException(Properties.Resources.TypeNotSupported, "value");
+ }
+
+ /// <summary>
+ /// Determines whether an explicit cast to JsonValue is provided from the specified type.
+ /// </summary>
+ /// <param name="type">The type to check.</param>
+ /// <returns>true if an explicit cast exists for the specified type, false otherwise.</returns>
+ internal static bool IsSupportedExplicitCastType(Type type)
+ {
+ TypeCode typeCode = Type.GetTypeCode(type);
+
+ switch (typeCode)
+ {
+ case TypeCode.Boolean:
+ case TypeCode.Byte:
+ case TypeCode.Char:
+ case TypeCode.DateTime:
+ case TypeCode.Decimal:
+ case TypeCode.Double:
+ case TypeCode.Int16:
+ case TypeCode.Int32:
+ case TypeCode.Int64:
+ case TypeCode.SByte:
+ case TypeCode.Single:
+ case TypeCode.String:
+ case TypeCode.UInt16:
+ case TypeCode.UInt32:
+ case TypeCode.UInt64:
+ return true;
+
+ default:
+ return type == typeof(DateTimeOffset) || type == typeof(Guid) || type == typeof(Uri) ||
+ type == typeof(List<object>) || type == typeof(Array) || type == typeof(object[]) ||
+ type == typeof(Dictionary<string, object>);
+ }
+ }
+
+ /// <summary>
+ /// Returns the value this object wraps (if any).
+ /// </summary>
+ /// <returns>The value wrapped by this instance or null if none.</returns>
+ internal virtual object Read()
+ {
+ return null;
+ }
+
+ /// <summary>
+ /// Serializes this object into the specified <see cref="XmlDictionaryWriter"/> instance.
+ /// </summary>
+ /// <param name="jsonWriter">An <see cref="XmlDictionaryWriter"/> instance to serialize this instance into.</param>
+ internal virtual void Save(XmlDictionaryWriter jsonWriter)
+ {
+ if (jsonWriter == null)
+ {
+ throw new ArgumentNullException("jsonWriter");
+ }
+
+ Stack<JsonValue> objectStack = new Stack<JsonValue>();
+ Stack<int> indexStack = new Stack<int>();
+ int currentIndex = 0;
+ JsonValue currentValue = this;
+
+ OnSaveStarted();
+
+ WriteAttributeString(jsonWriter);
+
+ while (currentIndex < currentValue.Count || objectStack.Count > 0)
+ {
+ if (currentValue.Count > currentIndex)
+ {
+ JsonValue nextValue = currentValue.WriteStartElementAndGetNext(jsonWriter, currentIndex);
+
+ if (JsonValue.IsJsonCollection(nextValue))
+ {
+ nextValue.OnSaveStarted();
+ nextValue.WriteAttributeString(jsonWriter);
+
+ objectStack.Push(currentValue);
+ indexStack.Push(currentIndex);
+ currentValue = nextValue;
+ currentIndex = 0;
+ }
+ else
+ {
+ if (nextValue == null)
+ {
+ jsonWriter.WriteAttributeString(JXmlToJsonValueConverter.TypeAttributeName, JXmlToJsonValueConverter.NullAttributeValue);
+ }
+ else
+ {
+ nextValue.Save(jsonWriter);
+ }
+
+ currentIndex++;
+ jsonWriter.WriteEndElement();
+ }
+ }
+ else
+ {
+ if (objectStack.Count > 0)
+ {
+ currentValue.OnSaveEnded();
+ jsonWriter.WriteEndElement();
+
+ currentValue = objectStack.Pop();
+ currentIndex = indexStack.Pop() + 1;
+ }
+ }
+ }
+
+ OnSaveEnded();
+ }
+
+ /// <summary>
+ /// Returns an enumerator which iterates through the values in this object.
+ /// </summary>
+ /// <returns>An <see cref="System.Collections.IEnumerator"/> which iterates through the values in this object.</returns>
+ /// <remarks>This method is the virtual version of the IEnumerator.GetEnumerator method and is provided to allow derived classes to implement the
+ /// appropriate version of the generic interface (enumerator of values or key/value pairs).</remarks>
+ [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate",
+ Justification = "This method is a virtual version of the IEnumerable.GetEnumerator method.")]
+ [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures",
+ Justification = "This class is a collection that is properly represented by the nested generic type.")]
+ protected virtual IEnumerator<KeyValuePair<string, JsonValue>> GetKeyValuePairEnumerator()
+ {
+ yield break;
+ }
+
+ /// <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="index">The index within this collection.</param>
+ /// <returns>The next item in the collection, or null of there are no more items.</returns>
+ internal virtual JsonValue WriteStartElementAndGetNext(XmlDictionaryWriter jsonWriter, int index)
+ {
+ return null;
+ }
+
+ /// <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 virtual void WriteAttributeString(XmlDictionaryWriter jsonWriter)
+ {
+ }
+
+ /// <summary>
+ /// Callback method called when a Save operation is starting for this instance.
+ /// </summary>
+ protected virtual void OnSaveStarted()
+ {
+ }
+
+ /// <summary>
+ /// Callback method called when a Save operation is finished for this instance.
+ /// </summary>
+ protected virtual void OnSaveEnded()
+ {
+ }
+
+ /// <summary>
+ /// Called internally to raise the <see cref="Changing"/> event.
+ /// </summary>
+ /// <param name="sender">The object which caused the event to be raised.</param>
+ /// <param name="eventArgs">The arguments to the event.</param>
+ [SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate",
+ Justification = "This is a helper function used to raise the event.")]
+ [SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers",
+ Justification = "This is not externally visible, since the constructor for this class is internal (cannot be directly derived) and all its subclasses are sealed.")]
+ protected void RaiseChangingEvent(object sender, JsonValueChangeEventArgs eventArgs)
+ {
+ EventHandler<JsonValueChangeEventArgs> changing = OnChanging;
+ if (changing != null)
+ {
+ changing(sender, eventArgs);
+ }
+ }
+
+ /// <summary>
+ /// Called internally to raise the <see cref="Changed"/> event.
+ /// </summary>
+ /// <param name="sender">The object which caused the event to be raised.</param>
+ /// <param name="eventArgs">The arguments to the event.</param>
+ [SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate",
+ Justification = "This is a helper function used to raise the event.")]
+ [SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers",
+ Justification = "This is not externally visible, since the constructor for this class is internal (cannot be directly derived) and all its subclasses are sealed.")]
+ protected void RaiseChangedEvent(object sender, JsonValueChangeEventArgs eventArgs)
+ {
+ EventHandler<JsonValueChangeEventArgs> changed = OnChanged;
+ if (changed != null)
+ {
+ changed(sender, eventArgs);
+ }
+ }
+
+ private static bool IsJsonCollection(JsonValue value)
+ {
+ return value != null && (value.JsonType == JsonType.Array || value.JsonType == JsonType.Object);
+ }
+
+ /// <summary>
+ /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.String"/> object.
+ /// </summary>
+ /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.String"/> object.</param>
+ /// <returns>The <see cref="System.String"/> initialized with the <see cref="System.Json.JsonValue"/> value specified or null if value is null.</returns>
+ public static explicit operator string(JsonValue value)
+ {
+ return CastValue<string>(value);
+ }
+
+ /// <summary>
+ /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.Double"/> object.
+ /// </summary>
+ /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.Double"/> object.</param>
+ /// <returns>The <see cref="System.Double"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
+ public static explicit operator double(JsonValue value)
+ {
+ return CastValue<double>(value);
+ }
+
+ /// <summary>
+ /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.Single"/> object.
+ /// </summary>
+ /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.Single"/> object.</param>
+ /// <returns>The <see cref="System.Single"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
+ public static explicit operator float(JsonValue value)
+ {
+ return CastValue<float>(value);
+ }
+
+ /// <summary>
+ /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.Decimal"/> object.
+ /// </summary>
+ /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.Decimal"/> object.</param>
+ /// <returns>The <see cref="System.Decimal"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
+ public static explicit operator decimal(JsonValue value)
+ {
+ return CastValue<decimal>(value);
+ }
+
+ /// <summary>
+ /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.Int64"/> object.
+ /// </summary>
+ /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.Int64"/> object.</param>
+ /// <returns>The <see cref="System.Int64"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
+ public static explicit operator long(JsonValue value)
+ {
+ return CastValue<long>(value);
+ }
+
+ /// <summary>
+ /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.UInt64"/> object.
+ /// </summary>
+ /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.UInt64"/> object.</param>
+ /// <returns>The <see cref="System.UInt64"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
+ [CLSCompliant(false)]
+ public static explicit operator ulong(JsonValue value)
+ {
+ return CastValue<ulong>(value);
+ }
+
+ /// <summary>
+ /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.Int32"/> object.
+ /// </summary>
+ /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.Int32"/> object.</param>
+ /// <returns>The <see cref="System.Int32"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
+ public static explicit operator int(JsonValue value)
+ {
+ return CastValue<int>(value);
+ }
+
+ /// <summary>
+ /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.UInt32"/> object.
+ /// </summary>
+ /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.UInt32"/> object.</param>
+ /// <returns>The <see cref="System.UInt32"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
+ [CLSCompliant(false)]
+ public static explicit operator uint(JsonValue value)
+ {
+ return CastValue<uint>(value);
+ }
+
+ /// <summary>
+ /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.Int16"/> object.
+ /// </summary>
+ /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.Int16"/> object.</param>
+ /// <returns>The <see cref="System.Int16"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
+ public static explicit operator short(JsonValue value)
+ {
+ return CastValue<short>(value);
+ }
+
+ /// <summary>
+ /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.UInt16"/> object.
+ /// </summary>
+ /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.UInt16"/> object.</param>
+ /// <returns>The <see cref="System.UInt16"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
+ [CLSCompliant(false)]
+ public static explicit operator ushort(JsonValue value)
+ {
+ return CastValue<ushort>(value);
+ }
+
+ /// <summary>
+ /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.SByte"/> object.
+ /// </summary>
+ /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.SByte"/> object.</param>
+ /// <returns>The <see cref="System.SByte"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
+ [CLSCompliant(false)]
+ public static explicit operator sbyte(JsonValue value)
+ {
+ return CastValue<sbyte>(value);
+ }
+
+ /// <summary>
+ /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.Byte"/> object.
+ /// </summary>
+ /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.Byte"/> object.</param>
+ /// <returns>The <see cref="System.Byte"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
+ public static explicit operator byte(JsonValue value)
+ {
+ return CastValue<byte>(value);
+ }
+
+ /// <summary>
+ /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.Uri"/> object.
+ /// </summary>
+ /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.Uri"/> object.</param>
+ /// <returns>The <see cref="System.Uri"/> initialized with the <see cref="System.Json.JsonValue"/> value specified or null if value is null.</returns>
+ public static explicit operator Uri(JsonValue value)
+ {
+ return CastValue<Uri>(value);
+ }
+
+ /// <summary>
+ /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.Guid"/> object.
+ /// </summary>
+ /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.Guid"/> object.</param>
+ /// <returns>The <see cref="System.Guid"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
+ public static explicit operator Guid(JsonValue value)
+ {
+ return CastValue<Guid>(value);
+ }
+
+ /// <summary>
+ /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.DateTime"/> object.
+ /// </summary>
+ /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.DateTime"/> object.</param>
+ /// <returns>The <see cref="System.DateTime"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
+ public static explicit operator DateTime(JsonValue value)
+ {
+ return CastValue<DateTime>(value);
+ }
+
+ /// <summary>
+ /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.Char"/> object.
+ /// </summary>
+ /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.Char"/> object.</param>
+ /// <returns>The <see cref="System.Char"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
+ public static explicit operator char(JsonValue value)
+ {
+ return CastValue<char>(value);
+ }
+
+ /// <summary>
+ /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.Boolean"/> object.
+ /// </summary>
+ /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.Boolean"/> object.</param>
+ /// <returns>The <see cref="System.Boolean"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
+ public static explicit operator bool(JsonValue value)
+ {
+ return CastValue<bool>(value);
+ }
+
+ /// <summary>
+ /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.DateTimeOffset"/> object.
+ /// </summary>
+ /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.DateTimeOffset"/> object.</param>
+ /// <returns>The <see cref="System.DateTimeOffset"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
+ public static explicit operator DateTimeOffset(JsonValue value)
+ {
+ return CastValue<DateTimeOffset>(value);
+ }
+
+ /// <summary>
+ /// Enables implicit casts from type <see cref="System.Boolean"/> to a <see cref="System.Json.JsonPrimitive"/>.
+ /// </summary>
+ /// <param name="value">The <see cref="System.Boolean"/> instance used to initialize the <see cref="System.Json.JsonPrimitive"/>.</param>
+ /// <returns>The <see cref="System.Json.JsonValue"/> initialized with the <see cref="System.Boolean"/> specified.</returns>
+ public static implicit operator JsonValue(bool value)
+ {
+ return new JsonPrimitive(value);
+ }
+
+ /// <summary>
+ /// Enables implicit casts from type <see cref="System.Byte"/> to a <see cref="System.Json.JsonPrimitive"/>.
+ /// </summary>
+ /// <param name="value">The <see cref="System.Byte"/> instance used to initialize the <see cref="System.Json.JsonPrimitive"/>.</param>
+ /// <returns>The <see cref="System.Json.JsonValue"/> initialized with the <see cref="System.Byte"/> specified.</returns>
+ public static implicit operator JsonValue(byte value)
+ {
+ return new JsonPrimitive(value);
+ }
+
+ /// <summary>
+ /// Enables implicit casts from type <see cref="System.Decimal"/> to a <see cref="System.Json.JsonPrimitive"/>.
+ /// </summary>
+ /// <param name="value">The <see cref="System.Decimal"/> instance used to initialize the <see cref="System.Json.JsonPrimitive"/>.</param>
+ /// <returns>The <see cref="System.Json.JsonValue"/> initialized with the <see cref="System.Decimal"/> specified.</returns>
+ public static implicit operator JsonValue(decimal value)
+ {
+ return new JsonPrimitive(value);
+ }
+
+ /// <summary>
+ /// Enables implicit casts from type <see cref="System.Double"/> to a <see cref="System.Json.JsonPrimitive"/>.
+ /// </summary>
+ /// <param name="value">The <see cref="System.Double"/> instance used to initialize the <see cref="System.Json.JsonPrimitive"/>.</param>
+ /// <returns>The <see cref="System.Json.JsonValue"/> initialized with the <see cref="System.Double"/> specified.</returns>
+ public static implicit operator JsonValue(double value)
+ {
+ return new JsonPrimitive(value);
+ }
+
+ /// <summary>
+ /// Enables implicit casts from type <see cref="System.Int16"/> to a <see cref="System.Json.JsonPrimitive"/>.
+ /// </summary>
+ /// <param name="value">The <see cref="System.Int16"/> instance used to initialize the <see cref="System.Json.JsonPrimitive"/>.</param>
+ /// <returns>The <see cref="System.Json.JsonValue"/> initialized with the <see cref="System.Int16"/> specified.</returns>
+ public static implicit operator JsonValue(short value)
+ {
+ return new JsonPrimitive(value);
+ }
+
+ /// <summary>
+ /// Enables implicit casts from type <see cref="System.Int32"/> to a <see cref="System.Json.JsonPrimitive"/>.
+ /// </summary>
+ /// <param name="value">The <see cref="System.Int32"/> instance used to initialize the <see cref="System.Json.JsonPrimitive"/>.</param>
+ /// <returns>The <see cref="System.Json.JsonValue"/> initialized with the <see cref="System.Int32"/> specified.</returns>
+ public static implicit operator JsonValue(int value)
+ {
+ return new JsonPrimitive(value);
+ }
+
+ /// <summary>
+ /// Enables implicit casts from type <see cref="System.Int64"/> to a <see cref="System.Json.JsonPrimitive"/>.
+ /// </summary>
+ /// <param name="value">The <see cref="System.Int64"/> instance used to initialize the <see cref="System.Json.JsonPrimitive"/>.</param>
+ /// <returns>The <see cref="System.Json.JsonValue"/> initialized with the <see cref="System.Int64"/> specified.</returns>
+ public static implicit operator JsonValue(long value)
+ {
+ return new JsonPrimitive(value);
+ }
+
+ /// <summary>
+ /// Enables implicit casts from type <see cref="System.Single"/> to a <see cref="System.Json.JsonPrimitive"/>.
+ /// </summary>
+ /// <param name="value">The <see cref="System.Single"/> instance used to initialize the <see cref="System.Json.JsonPrimitive"/>.</param>
+ /// <returns>The <see cref="System.Json.JsonValue"/> initialized with the <see cref="System.Single"/> specified.</returns>
+ public static implicit operator JsonValue(float value)
+ {
+ return new JsonPrimitive(value);
+ }
+
+ /// <summary>
+ /// Enables implicit casts from type <see cref="System.String"/> to a <see cref="System.Json.JsonPrimitive"/>.
+ /// </summary>
+ /// <param name="value">The <see cref="System.String"/> instance used to initialize the <see cref="System.Json.JsonPrimitive"/>.</param>
+ /// <returns>The <see cref="System.Json.JsonValue"/> initialized with the <see cref="System.String"/> specified, or null if the value is null.</returns>
+ [SuppressMessage("Microsoft.Design", "CA1057:StringUriOverloadsCallSystemUriOverloads",
+ Justification = "This operator does not intend to represent a Uri overload.")]
+ public static implicit operator JsonValue(string value)
+ {
+ return value == null ? null : new JsonPrimitive(value);
+ }
+
+ /// <summary>
+ /// Enables implicit casts from type <see cref="System.Char"/> to a <see cref="System.Json.JsonPrimitive"/>.
+ /// </summary>
+ /// <param name="value">The <see cref="System.Char"/> instance used to initialize the <see cref="System.Json.JsonPrimitive"/>.</param>
+ /// <returns>The <see cref="System.Json.JsonValue"/> initialized with the <see cref="System.Char"/> specified.</returns>
+ public static implicit operator JsonValue(char value)
+ {
+ return new JsonPrimitive(value);
+ }
+
+ /// <summary>
+ /// Enables implicit casts from type <see cref="System.DateTime"/> to a <see cref="System.Json.JsonPrimitive"/>.
+ /// </summary>
+ /// <param name="value">The <see cref="System.DateTime"/> instance used to initialize the <see cref="System.Json.JsonPrimitive"/>.</param>
+ /// <returns>The <see cref="System.Json.JsonValue"/> initialized with the <see cref="System.DateTime"/> specified.</returns>
+ public static implicit operator JsonValue(DateTime value)
+ {
+ return new JsonPrimitive(value);
+ }
+
+ /// <summary>
+ /// Enables implicit casts from type <see cref="System.Guid"/> to a <see cref="System.Json.JsonPrimitive"/>.
+ /// </summary>
+ /// <param name="value">The <see cref="System.Guid"/> instance used to initialize the <see cref="System.Json.JsonPrimitive"/>.</param>
+ /// <returns>The <see cref="System.Json.JsonValue"/> initialized with the <see cref="System.Guid"/> specified.</returns>
+ public static implicit operator JsonValue(Guid value)
+ {
+ return new JsonPrimitive(value);
+ }
+
+ /// <summary>
+ /// Enables implicit casts from type <see cref="System.Uri"/> to a <see cref="System.Json.JsonPrimitive"/>.
+ /// </summary>
+ /// <param name="value">The <see cref="System.Uri"/> instance used to initialize the <see cref="System.Json.JsonPrimitive"/>.</param>
+ /// <returns>The <see cref="System.Json.JsonValue"/> initialized with the <see cref="System.Uri"/> specified, or null if the value is null.</returns>
+ public static implicit operator JsonValue(Uri value)
+ {
+ return value == null ? null : new JsonPrimitive(value);
+ }
+
+ /// <summary>
+ /// Enables implicit casts from type <see cref="System.SByte"/> to a <see cref="System.Json.JsonPrimitive"/>.
+ /// </summary>
+ /// <param name="value">The <see cref="System.SByte"/> instance used to initialize the <see cref="System.Json.JsonPrimitive"/>.</param>
+ /// <returns>The <see cref="System.Json.JsonValue"/> initialized with the <see cref="System.SByte"/> specified.</returns>
+ [CLSCompliant(false)]
+ public static implicit operator JsonValue(sbyte value)
+ {
+ return new JsonPrimitive(value);
+ }
+
+ /// <summary>
+ /// Enables implicit casts from type <see cref="System.UInt16"/> to a <see cref="System.Json.JsonPrimitive"/>.
+ /// </summary>
+ /// <param name="value">The <see cref="System.UInt16"/> instance used to initialize the <see cref="System.Json.JsonPrimitive"/>.</param>
+ /// <returns>The <see cref="System.Json.JsonValue"/> initialized with the <see cref="System.UInt16"/> specified.</returns>
+ [CLSCompliant(false)]
+ public static implicit operator JsonValue(ushort value)
+ {
+ return new JsonPrimitive(value);
+ }
+
+ /// <summary>
+ /// Enables implicit casts from type <see cref="System.UInt32"/> to a <see cref="System.Json.JsonPrimitive"/>.
+ /// </summary>
+ /// <param name="value">The <see cref="System.UInt32"/> instance used to initialize the <see cref="System.Json.JsonPrimitive"/>.</param>
+ /// <returns>The <see cref="System.Json.JsonValue"/> initialized with the <see cref="System.UInt32"/> specified.</returns>
+ [CLSCompliant(false)]
+ public static implicit operator JsonValue(uint value)
+ {
+ return new JsonPrimitive(value);
+ }
+
+ /// <summary>
+ /// Enables implicit casts from type <see cref="System.UInt64"/> to a <see cref="System.Json.JsonPrimitive"/>.
+ /// </summary>
+ /// <param name="value">The <see cref="System.UInt64"/> instance used to initialize the <see cref="System.Json.JsonPrimitive"/>.</param>
+ /// <returns>The <see cref="System.Json.JsonValue"/> initialized with the <see cref="System.UInt64"/> specified.</returns>
+ [CLSCompliant(false)]
+ public static implicit operator JsonValue(ulong value)
+ {
+ return new JsonPrimitive(value);
+ }
+
+ /// <summary>
+ /// Enables implicit casts from type <see cref="System.DateTimeOffset"/> to a <see cref="System.Json.JsonPrimitive"/>.
+ /// </summary>
+ /// <param name="value">The <see cref="System.DateTimeOffset"/> instance used to initialize the <see cref="System.Json.JsonPrimitive"/>.</param>
+ /// <returns>The <see cref="System.Json.JsonValue"/> initialized with the <see cref="System.DateTimeOffset"/> specified.</returns>
+ public static implicit operator JsonValue(DateTimeOffset value)
+ {
+ return new JsonPrimitive(value);
+ }
+ }
+}
diff --git a/mcs/class/System.Json.Microsoft/System.Json/JsonValueChange.cs b/mcs/class/System.Json.Microsoft/System.Json/JsonValueChange.cs
new file mode 100644
index 00000000000..2182e622c77
--- /dev/null
+++ b/mcs/class/System.Json.Microsoft/System.Json/JsonValueChange.cs
@@ -0,0 +1,30 @@
+// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
+
+namespace System.Json
+{
+ /// <summary>
+ /// Specifies the event type when an event is raised for a <see cref="System.Json.JsonValue"/>.
+ /// </summary>
+ public enum JsonValueChange
+ {
+ /// <summary>
+ /// An element has been or will be added to the collection.
+ /// </summary>
+ Add,
+
+ /// <summary>
+ /// An element has been or will be removed from the collection.
+ /// </summary>
+ Remove,
+
+ /// <summary>
+ /// An element has been or will be replaced in the collection. Used on indexers.
+ /// </summary>
+ Replace,
+
+ /// <summary>
+ /// All elements of the collection have been or will be removed.
+ /// </summary>
+ Clear,
+ }
+}
diff --git a/mcs/class/System.Json.Microsoft/System.Json/JsonValueChangeEventArgs.cs b/mcs/class/System.Json.Microsoft/System.Json/JsonValueChangeEventArgs.cs
new file mode 100644
index 00000000000..cf7097b2047
--- /dev/null
+++ b/mcs/class/System.Json.Microsoft/System.Json/JsonValueChangeEventArgs.cs
@@ -0,0 +1,98 @@
+// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
+
+namespace System.Json
+{
+ /// <summary>
+ /// Provide data for the <see cref="System.Json.JsonValue.Changing"/> and <see cref="System.Json.JsonValue.Changed"/> events.
+ /// </summary>
+ public class JsonValueChangeEventArgs : EventArgs
+ {
+ private JsonValue child;
+ private JsonValueChange change;
+ private int index;
+ private string key;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="System.Json.JsonValueChangeEventArgs"/> class for
+ /// changes in a <see cref="System.Json.JsonArray"/>.
+ /// </summary>
+ /// <param name="child">The <see cref="System.Json.JsonValue"/> instance which will be or has been modified.</param>
+ /// <param name="change">The type of change of the <see cref="System.Json.JsonValue"/> event.</param>
+ /// <param name="index">The index of the element being changed in a <see cref="System.Json.JsonArray"/>.</param>
+ public JsonValueChangeEventArgs(JsonValue child, JsonValueChange change, int index)
+ {
+ if (index < 0)
+ {
+ throw new ArgumentOutOfRangeException("index", RS.Format(Properties.Resources.ArgumentMustBeGreaterThanOrEqualTo, index, 0));
+ }
+
+ this.child = child;
+ this.change = change;
+ this.index = index;
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="System.Json.JsonValueChangeEventArgs"/> class for
+ /// changes in a <see cref="System.Json.JsonObject"/>.
+ /// </summary>
+ /// <param name="child">The <see cref="System.Json.JsonValue"/> instance which will be or has been modified.</param>
+ /// <param name="change">The type of change of the <see cref="System.Json.JsonValue"/> event.</param>
+ /// <param name="key">The key of the element being changed in a <see cref="System.Json.JsonObject"/>.</param>
+ public JsonValueChangeEventArgs(JsonValue child, JsonValueChange change, string key)
+ {
+ if (change != JsonValueChange.Clear)
+ {
+ if (key == null)
+ {
+ throw new ArgumentNullException("key");
+ }
+ }
+
+ this.child = child;
+ this.change = change;
+ index = -1;
+ this.key = key;
+ }
+
+ /// <summary>
+ /// Gets the child which will be or has been modified.
+ /// </summary>
+ /// <remarks><p>This property is <code>null</code> for <see cref="System.Json.JsonValueChange.Clear"/> event types
+ /// raised by <see cref="System.Json.JsonValue"/> instances.</p>
+ /// <p>For <see cref="System.Json.JsonValueChange">Replace</see> events, this property contains the new value in
+ /// the <see cref="System.Json.JsonValue.Changing"/> event, and the old value (the one being replaced) in the
+ /// <see cref="System.Json.JsonValue.Changed"/> event.</p></remarks>
+ public JsonValue Child
+ {
+ get { return child; }
+ }
+
+ /// <summary>
+ /// Gets the type of change.
+ /// </summary>
+ public JsonValueChange Change
+ {
+ get { return change; }
+ }
+
+ /// <summary>
+ /// Gets the index in the <see cref="System.Json.JsonArray"/> where the change happened, or
+ /// <code>-1</code> if the change happened in a <see cref="System.Json.JsonValue"/> of a different type.
+ /// </summary>
+ public int Index
+ {
+ get { return index; }
+ }
+
+ /// <summary>
+ /// Gets the key in the <see cref="System.Json.JsonObject"/> where the change happened, or
+ /// <code>null</code> if the change happened in a <see cref="System.Json.JsonValue"/> of a different type.
+ /// </summary>
+ /// <remarks>This property can also be <code>null</code> if the event type is
+ /// <see cref="System.Json.JsonValueChange">Clear</see>.</remarks>
+ public string Key
+ {
+ get { return key; }
+ }
+ }
+}
diff --git a/mcs/class/System.Json.Microsoft/System.Json/JsonValueDynamicMetaObject.cs b/mcs/class/System.Json.Microsoft/System.Json/JsonValueDynamicMetaObject.cs
new file mode 100644
index 00000000000..f38f98fc4f2
--- /dev/null
+++ b/mcs/class/System.Json.Microsoft/System.Json/JsonValueDynamicMetaObject.cs
@@ -0,0 +1,384 @@
+// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
+#if FEATURE_DYNAMIC
+using System.Collections.Generic;
+using System.Dynamic;
+using System.Linq.Expressions;
+using System.Reflection;
+using System.Runtime.Serialization.Json;
+
+namespace System.Json
+{
+ /// <summary>
+ /// This class provides dynamic behavior support for the JsonValue types.
+ /// </summary>
+ internal class JsonValueDynamicMetaObject : DynamicMetaObject
+ {
+ private static readonly MethodInfo _getValueByIndexMethodInfo = typeof(JsonValue).GetMethod("GetValue", new Type[] { typeof(int) });
+ private static readonly MethodInfo _getValueByKeyMethodInfo = typeof(JsonValue).GetMethod("GetValue", new Type[] { typeof(string) });
+ private static readonly MethodInfo _setValueByIndexMethodInfo = typeof(JsonValue).GetMethod("SetValue", new Type[] { typeof(int), typeof(object) });
+ private static readonly MethodInfo _setValueByKeyMethodInfo = typeof(JsonValue).GetMethod("SetValue", new Type[] { typeof(string), typeof(object) });
+ private static readonly MethodInfo _castValueMethodInfo = typeof(JsonValue).GetMethod("CastValue", new Type[] { typeof(JsonValue) });
+ private static readonly MethodInfo _changeTypeMethodInfo = typeof(Convert).GetMethod("ChangeType", new Type[] { typeof(object), typeof(Type) });
+
+ /// <summary>
+ /// Class constructor.
+ /// </summary>
+ /// <param name="parameter">The expression representing this <see cref="DynamicMetaObject"/> during the dynamic binding process.</param>
+ /// <param name="value">The runtime value represented by the <see cref="DynamicMetaObject"/>.</param>
+ internal JsonValueDynamicMetaObject(Expression parameter, JsonValue value)
+ : base(parameter, BindingRestrictions.Empty, value)
+ {
+ }
+
+ /// <summary>
+ /// Gets the default binding restrictions for this type.
+ /// </summary>
+ private BindingRestrictions DefaultRestrictions
+ {
+ get { return BindingRestrictions.GetTypeRestriction(Expression, LimitType); }
+ }
+
+ /// <summary>
+ /// Implements dynamic cast for JsonValue types.
+ /// </summary>
+ /// <param name="binder">An instance of the <see cref="ConvertBinder"/> that represents the details of the dynamic operation.</param>
+ /// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
+ public override DynamicMetaObject BindConvert(ConvertBinder binder)
+ {
+ if (binder == null)
+ {
+ throw new ArgumentNullException("binder");
+ }
+
+ Expression expression = Expression;
+
+ bool implicitCastSupported =
+ binder.Type.IsAssignableFrom(LimitType) ||
+ binder.Type == typeof(IEnumerable<KeyValuePair<string, JsonValue>>) ||
+ binder.Type == typeof(IDynamicMetaObjectProvider) ||
+ binder.Type == typeof(object);
+
+ if (!implicitCastSupported)
+ {
+ if (JsonValue.IsSupportedExplicitCastType(binder.Type))
+ {
+ Expression instance = Expression.Convert(Expression, LimitType);
+ expression = Expression.Call(_castValueMethodInfo.MakeGenericMethod(binder.Type), new Expression[] { instance });
+ }
+ else
+ {
+ string exceptionMessage = RS.Format(Properties.Resources.CannotCastJsonValue, LimitType.FullName, binder.Type.FullName);
+ expression = Expression.Throw(Expression.Constant(new InvalidCastException(exceptionMessage)), typeof(object));
+ }
+ }
+
+ expression = Expression.Convert(expression, binder.Type);
+
+ return new DynamicMetaObject(expression, DefaultRestrictions);
+ }
+
+ /// <summary>
+ /// Implements setter for dynamic indexer by index (JsonArray)
+ /// </summary>
+ /// <param name="binder">An instance of the <see cref="GetIndexBinder"/> that represents the details of the dynamic operation.</param>
+ /// <param name="indexes">An array of <see cref="DynamicMetaObject"/> instances - indexes for the get index operation.</param>
+ /// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
+ public override DynamicMetaObject BindGetIndex(GetIndexBinder binder, DynamicMetaObject[] indexes)
+ {
+ if (binder == null)
+ {
+ throw new ArgumentNullException("binder");
+ }
+
+ if (indexes == null)
+ {
+ throw new ArgumentNullException("indexes");
+ }
+
+ Expression indexExpression;
+ if (!JsonValueDynamicMetaObject.TryGetIndexExpression(indexes, out indexExpression))
+ {
+ return new DynamicMetaObject(indexExpression, DefaultRestrictions);
+ }
+
+ MethodInfo methodInfo = indexExpression.Type == typeof(string) ? _getValueByKeyMethodInfo : _getValueByIndexMethodInfo;
+ Expression[] args = new Expression[] { indexExpression };
+
+ return GetMethodMetaObject(methodInfo, args);
+ }
+
+ /// <summary>
+ /// Implements getter for dynamic indexer by index (JsonArray).
+ /// </summary>
+ /// <param name="binder">An instance of the <see cref="SetIndexBinder"/> that represents the details of the dynamic operation.</param>
+ /// <param name="indexes">An array of <see cref="DynamicMetaObject"/> instances - indexes for the set index operation.</param>
+ /// <param name="value">The <see cref="DynamicMetaObject"/> representing the value for the set index operation.</param>
+ /// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
+ public override DynamicMetaObject BindSetIndex(SetIndexBinder binder, DynamicMetaObject[] indexes, DynamicMetaObject value)
+ {
+ if (binder == null)
+ {
+ throw new ArgumentNullException("binder");
+ }
+
+ if (indexes == null)
+ {
+ throw new ArgumentNullException("indexes");
+ }
+
+ if (value == null)
+ {
+ throw new ArgumentNullException("value");
+ }
+
+ Expression indexExpression;
+ if (!JsonValueDynamicMetaObject.TryGetIndexExpression(indexes, out indexExpression))
+ {
+ return new DynamicMetaObject(indexExpression, DefaultRestrictions);
+ }
+
+ MethodInfo methodInfo = indexExpression.Type == typeof(string) ? _setValueByKeyMethodInfo : _setValueByIndexMethodInfo;
+ Expression[] args = new Expression[] { indexExpression, Expression.Convert(value.Expression, typeof(object)) };
+
+ return GetMethodMetaObject(methodInfo, args);
+ }
+
+ /// <summary>
+ /// Implements getter for dynamic indexer by key (JsonObject).
+ /// </summary>
+ /// <param name="binder">An instance of the <see cref="GetMemberBinder"/> that represents the details of the dynamic operation.</param>
+ /// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
+ public override DynamicMetaObject BindGetMember(GetMemberBinder binder)
+ {
+ if (binder == null)
+ {
+ throw new ArgumentNullException("binder");
+ }
+
+ PropertyInfo propInfo = LimitType.GetProperty(binder.Name, BindingFlags.Instance | BindingFlags.Public);
+
+ if (propInfo != null)
+ {
+ return base.BindGetMember(binder);
+ }
+
+ Expression[] args = new Expression[] { Expression.Constant(binder.Name) };
+
+ return GetMethodMetaObject(_getValueByKeyMethodInfo, args);
+ }
+
+ /// <summary>
+ /// Implements setter for dynamic indexer by key (JsonObject).
+ /// </summary>
+ /// <param name="binder">An instance of the <see cref="SetMemberBinder"/> that represents the details of the dynamic operation.</param>
+ /// <param name="value">The <see cref="DynamicMetaObject"/> representing the value for the set member operation.</param>
+ /// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
+ public override DynamicMetaObject BindSetMember(SetMemberBinder binder, DynamicMetaObject value)
+ {
+ if (binder == null)
+ {
+ throw new ArgumentNullException("binder");
+ }
+
+ if (value == null)
+ {
+ throw new ArgumentNullException("value");
+ }
+
+ Expression[] args = new Expression[] { Expression.Constant(binder.Name), Expression.Convert(value.Expression, typeof(object)) };
+
+ return GetMethodMetaObject(_setValueByKeyMethodInfo, args);
+ }
+
+ /// <summary>
+ /// Performs the binding of the dynamic invoke member operation.
+ /// Implemented to support extension methods defined in <see cref="JsonValueExtensions"/> type.
+ /// </summary>
+ /// <param name="binder">An instance of the InvokeMemberBinder that represents the details of the dynamic operation.</param>
+ /// <param name="args">An array of DynamicMetaObject instances - arguments to the invoke member operation.</param>
+ /// <returns>The new DynamicMetaObject representing the result of the binding.</returns>
+ public override DynamicMetaObject BindInvokeMember(InvokeMemberBinder binder, DynamicMetaObject[] args)
+ {
+ if (binder == null)
+ {
+ throw new ArgumentNullException("binder");
+ }
+
+ if (args == null)
+ {
+ throw new ArgumentNullException("args");
+ }
+
+ List<Type> argTypeList = new List<Type>();
+
+ for (int idx = 0; idx < args.Length; idx++)
+ {
+ argTypeList.Add(args[idx].LimitType);
+ }
+
+ MethodInfo methodInfo = Value.GetType().GetMethod(binder.Name, argTypeList.ToArray());
+
+ if (methodInfo == null)
+ {
+ argTypeList.Insert(0, typeof(JsonValue));
+
+ Type[] argTypes = argTypeList.ToArray();
+
+ methodInfo = JsonValueDynamicMetaObject.GetExtensionMethod(typeof(JsonValueExtensions), binder.Name, argTypes);
+
+ if (methodInfo != null)
+ {
+ Expression thisInstance = Expression.Convert(Expression, LimitType);
+ Expression[] argsExpression = new Expression[argTypes.Length];
+
+ argsExpression[0] = thisInstance;
+ for (int i = 0; i < args.Length; i++)
+ {
+ argsExpression[i + 1] = args[i].Expression;
+ }
+
+ Expression callExpression = Expression.Call(methodInfo, argsExpression);
+
+ if (methodInfo.ReturnType == typeof(void))
+ {
+ callExpression = Expression.Block(callExpression, Expression.Default(binder.ReturnType));
+ }
+ else
+ {
+ callExpression = Expression.Convert(Expression.Call(methodInfo, argsExpression), binder.ReturnType);
+ }
+
+ return new DynamicMetaObject(callExpression, DefaultRestrictions);
+ }
+ }
+
+ return base.BindInvokeMember(binder, args);
+ }
+
+ /// <summary>
+ /// Returns the enumeration of all dynamic member names.
+ /// </summary>
+ /// <returns>An <see cref="IEnumerable{T}"/> of string reprenseting the dynamic member names.</returns>
+ public override IEnumerable<string> GetDynamicMemberNames()
+ {
+ JsonValue jsonValue = Value as JsonValue;
+
+ if (jsonValue != null)
+ {
+ List<string> names = new List<string>();
+
+ foreach (KeyValuePair<string, JsonValue> pair in jsonValue)
+ {
+ names.Add(pair.Key);
+ }
+
+ return names;
+ }
+
+ return base.GetDynamicMemberNames();
+ }
+
+ /// <summary>
+ /// Gets a <see cref="MethodInfo"/> instance for the specified method name in the specified type.
+ /// </summary>
+ /// <param name="extensionProviderType">The extension provider type.</param>
+ /// <param name="methodName">The name of the method to get the info for.</param>
+ /// <param name="argTypes">The types of the method arguments.</param>
+ /// <returns>A <see cref="MethodInfo"/>instance or null if the method cannot be resolved.</returns>
+ private static MethodInfo GetExtensionMethod(Type extensionProviderType, string methodName, Type[] argTypes)
+ {
+ MethodInfo methodInfo = null;
+ MethodInfo[] methods = extensionProviderType.GetMethods();
+
+ foreach (MethodInfo info in methods)
+ {
+ if (info.Name == methodName)
+ {
+ methodInfo = info;
+
+ if (!info.IsGenericMethodDefinition)
+ {
+ bool paramsMatch = true;
+ ParameterInfo[] args = methodInfo.GetParameters();
+
+ if (args.Length == argTypes.Length)
+ {
+ for (int idx = 0; idx < args.Length; idx++)
+ {
+ if (!args[idx].ParameterType.IsAssignableFrom(argTypes[idx]))
+ {
+ paramsMatch = false;
+ break;
+ }
+ }
+
+ if (paramsMatch)
+ {
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return methodInfo;
+ }
+
+ /// <summary>
+ /// Attempts to get an expression for an index parameter.
+ /// </summary>
+ /// <param name="indexes">The operation indexes parameter.</param>
+ /// <param name="expression">A <see cref="Expression"/> to be initialized to the index expression if the operation is successful, otherwise an error expression.</param>
+ /// <returns>true the operation is successful, false otherwise.</returns>
+ private static bool TryGetIndexExpression(DynamicMetaObject[] indexes, out Expression expression)
+ {
+ if (indexes.Length == 1 && indexes[0] != null && indexes[0].Value != null)
+ {
+ DynamicMetaObject index = indexes[0];
+ Type indexType = indexes[0].Value.GetType();
+
+ switch (Type.GetTypeCode(indexType))
+ {
+ case TypeCode.Char:
+ case TypeCode.Int16:
+ case TypeCode.UInt16:
+ case TypeCode.Byte:
+ case TypeCode.SByte:
+ Expression argExp = Expression.Convert(index.Expression, typeof(object));
+ Expression typeExp = Expression.Constant(typeof(int));
+ expression = Expression.Convert(Expression.Call(_changeTypeMethodInfo, new Expression[] { argExp, typeExp }), typeof(int));
+ return true;
+
+ case TypeCode.Int32:
+ case TypeCode.String:
+ expression = index.Expression;
+ return true;
+ }
+
+ expression = Expression.Throw(Expression.Constant(new ArgumentException(RS.Format(Properties.Resources.InvalidIndexType, indexType))), typeof(object));
+ return false;
+ }
+
+ expression = Expression.Throw(Expression.Constant(new ArgumentException(Properties.Resources.NonSingleNonNullIndexNotSupported)), typeof(object));
+ return false;
+ }
+
+ /// <summary>
+ /// Gets a <see cref="DynamicMetaObject"/> for a method call.
+ /// </summary>
+ /// <param name="methodInfo">Info for the method to be performed.</param>
+ /// <param name="args">expression array representing the method arguments</param>
+ /// <returns>A meta object for the method call.</returns>
+ private DynamicMetaObject GetMethodMetaObject(MethodInfo methodInfo, Expression[] args)
+ {
+ Expression instance = Expression.Convert(Expression, LimitType);
+ Expression methodCall = Expression.Call(instance, methodInfo, args);
+ BindingRestrictions restrictions = DefaultRestrictions;
+
+ DynamicMetaObject metaObj = new DynamicMetaObject(methodCall, restrictions);
+
+ return metaObj;
+ }
+ }
+}
+#endif
diff --git a/mcs/class/System.Json.Microsoft/System.Json/JsonValueLinqExtensions.cs b/mcs/class/System.Json.Microsoft/System.Json/JsonValueLinqExtensions.cs
new file mode 100644
index 00000000000..5516a037371
--- /dev/null
+++ b/mcs/class/System.Json.Microsoft/System.Json/JsonValueLinqExtensions.cs
@@ -0,0 +1,37 @@
+// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
+
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Diagnostics.CodeAnalysis;
+
+namespace System.Json
+{
+ /// <summary>
+ /// This class extends the funcionality of the <see cref="JsonValue"/> type for better Linq support .
+ /// </summary>
+ [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Justification = "Linq is a technical name.")]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static class JsonValueLinqExtensions
+ {
+ /// <summary>
+ /// Extension method for creating a <see cref="JsonValue"/> from an <see cref="IEnumerable{T}"/> collection of <see cref="JsonValue"/> types.
+ /// </summary>
+ /// <param name="items">The enumerable instance.</param>
+ /// <returns>A <see cref="JsonArray"/> created from the specified items.</returns>
+ public static JsonArray ToJsonArray(this IEnumerable<JsonValue> items)
+ {
+ return new JsonArray(items);
+ }
+
+ /// <summary>
+ /// Extension method for creating a <see cref="JsonValue"/> from an <see cref="IEnumerable{T}"/> collection of <see cref="KeyValuePair{K,V}"/> of <see cref="String"/> and <see cref="JsonValue"/> types.
+ /// </summary>
+ /// <param name="items">The enumerable instance.</param>
+ /// <returns>A <see cref="JsonValue"/> created from the specified items.</returns>
+ [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "JsonValue implements the nested type in param.")]
+ public static JsonObject ToJsonObject(this IEnumerable<KeyValuePair<string, JsonValue>> items)
+ {
+ return new JsonObject(items);
+ }
+ }
+}
diff --git a/mcs/class/System.Json.Microsoft/System.Json/NGenWrapper.cs b/mcs/class/System.Json.Microsoft/System.Json/NGenWrapper.cs
new file mode 100644
index 00000000000..4a9e7b5c2a3
--- /dev/null
+++ b/mcs/class/System.Json.Microsoft/System.Json/NGenWrapper.cs
@@ -0,0 +1,48 @@
+// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
+
+namespace System.Json
+{
+ /// <summary>
+ /// Struct that wraps values which cause JIT compilation at runtime.
+ /// This Struct is added to solve the FxCop warning CA908 in JsonObject.cs.
+ /// </summary>
+ /// <typeparam name="T">Wrapped type.</typeparam>
+ internal struct NGenWrapper<T>
+ {
+ /// <summary>
+ /// Value of type T which represents the actual data which is currently in hold.
+ /// </summary>
+ public T Value;
+
+ /// <summary>
+ /// Creates an instance of the <see cref="System.Json.NGenWrapper{T}"/> class
+ /// </summary>
+ /// <param name="value">The wrapped object of T</param>
+ public NGenWrapper(T value)
+ {
+ Value = value;
+ }
+
+ /// <summary>
+ /// Cast operator from <see cref="System.Json.NGenWrapper{T}"/> to <typeparamref name="T"/>
+ /// </summary>
+ /// <param name="value">Object in type <see cref="System.Json.NGenWrapper{T}"/></param>
+ /// <returns>Object in type <typeparamref name="T">The wrapped element type</typeparamref></returns>
+ /// <typeparamref name="T">The wrapped element type</typeparamref>
+ public static implicit operator T(NGenWrapper<T> value)
+ {
+ return value.Value;
+ }
+
+ /// <summary>
+ /// Cast operator from <typeparamref name="T"/> to <see cref="System.Json.NGenWrapper{T}"/>
+ /// </summary>
+ /// <param name="value">Object in type <typeparamref name="T"/></param>
+ /// <returns>Object in type <see cref="System.Json.NGenWrapper{T}"/></returns>
+ /// <typeparamref name="T">The wrapped element type</typeparamref>
+ public static implicit operator NGenWrapper<T>(T value)
+ {
+ return new NGenWrapper<T>(value);
+ }
+ }
+}
diff --git a/mcs/class/System.Json.Microsoft/System.Json/Properties/AssemblyInfo.cs b/mcs/class/System.Json.Microsoft/System.Json/Properties/AssemblyInfo.cs
new file mode 100644
index 00000000000..f413e072853
--- /dev/null
+++ b/mcs/class/System.Json.Microsoft/System.Json/Properties/AssemblyInfo.cs
@@ -0,0 +1,12 @@
+// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
+
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+
+[assembly: AssemblyTitle("System.Json")]
+[assembly: AssemblyDescription("")]
+[assembly: Guid("6fd72360-ebfc-4097-96fa-2ee418c04f7b")]
diff --git a/mcs/class/System.Json.Microsoft/System.Json/Properties/Resources.Designer.cs b/mcs/class/System.Json.Microsoft/System.Json/Properties/Resources.Designer.cs
new file mode 100644
index 00000000000..5a0e1206de3
--- /dev/null
+++ b/mcs/class/System.Json.Microsoft/System.Json/Properties/Resources.Designer.cs
@@ -0,0 +1,216 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.239
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace System.Json.Properties {
+ using System;
+
+
+ /// <summary>
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ /// </summary>
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ /// <summary>
+ /// Returns the cached ResourceManager instance used by this class.
+ /// </summary>
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("System.Json.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ /// <summary>
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ /// </summary>
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to The argument &apos;{0}&apos; must be greater than or equal to {1}..
+ /// </summary>
+ internal static string ArgumentMustBeGreaterThanOrEqualTo {
+ get {
+ return ResourceManager.GetString("ArgumentMustBeGreaterThanOrEqualTo", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Unable to cast object of type &apos;{0}&apos; to type &apos;{1}&apos;..
+ /// </summary>
+ internal static string CannotCastJsonValue {
+ get {
+ return ResourceManager.GetString("CannotCastJsonValue", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to CannotReadAsType=Cannot read &apos;{0}&apos; as &apos;{1}&apos; type..
+ /// </summary>
+ internal static string CannotReadAsType {
+ get {
+ return ResourceManager.GetString("CannotReadAsType", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Cannot read JsonPrimitive value &apos;{0}&apos; as &apos;{1}&apos;..
+ /// </summary>
+ internal static string CannotReadPrimitiveAsType {
+ get {
+ return ResourceManager.GetString("CannotReadPrimitiveAsType", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to &apos;{0}&apos; does not contain a definition for property &apos;{1}&apos;..
+ /// </summary>
+ internal static string DynamicPropertyNotDefined {
+ get {
+ return ResourceManager.GetString("DynamicPropertyNotDefined", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to The input source is not correctly formatted..
+ /// </summary>
+ internal static string IncorrectJsonFormat {
+ get {
+ return ResourceManager.GetString("IncorrectJsonFormat", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to &apos;{0}&apos; type indexer is not supported on JsonValue of &apos;JsonType.{1}&apos; type..
+ /// </summary>
+ internal static string IndexerNotSupportedOnJsonType {
+ get {
+ return ResourceManager.GetString("IndexerNotSupportedOnJsonType", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Cannot convert null to &apos;{0}&apos; because it is a non-nullable value type..
+ /// </summary>
+ internal static string InvalidCastNonNullable {
+ get {
+ return ResourceManager.GetString("InvalidCastNonNullable", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Cannot cast JsonPrimitive value &apos;{0}&apos; as &apos;{1}&apos;. It is not in a valid date format..
+ /// </summary>
+ internal static string InvalidDateFormat {
+ get {
+ return ResourceManager.GetString("InvalidDateFormat", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Invalid &apos;{0}&apos; index type; only &apos;System.String&apos; and non-negative &apos;System.Int32&apos; types are supported..
+ /// </summary>
+ internal static string InvalidIndexType {
+ get {
+ return ResourceManager.GetString("InvalidIndexType", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Invalid JSON primitive: {0}..
+ /// </summary>
+ internal static string InvalidJsonPrimitive {
+ get {
+ return ResourceManager.GetString("InvalidJsonPrimitive", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Cannot cast &apos;{0}&apos; value &apos;{1}.{2}&apos; as a type of &apos;{3}&apos;. The provided string is not a valid relative or absolute &apos;{3}&apos;..
+ /// </summary>
+ internal static string InvalidUriFormat {
+ get {
+ return ResourceManager.GetString("InvalidUriFormat", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to An empty string cannot be parsed as JSON..
+ /// </summary>
+ internal static string JsonStringCannotBeEmpty {
+ get {
+ return ResourceManager.GetString("JsonStringCannotBeEmpty", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Null index or multidimensional indexing is not supported by this indexer; use &apos;System.Int32&apos; or &apos;System.String&apos; for array and object indexing respectively..
+ /// </summary>
+ internal static string NonSingleNonNullIndexNotSupported {
+ get {
+ return ResourceManager.GetString("NonSingleNonNullIndexNotSupported", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Cannot cast JsonPrimitive value &apos;{0}&apos; as &apos;{1}&apos;. The value is either too large or too small for the specified CLR type..
+ /// </summary>
+ internal static string OverflowReadAs {
+ get {
+ return ResourceManager.GetString("OverflowReadAs", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Object type not supported..
+ /// </summary>
+ internal static string TypeNotSupported {
+ get {
+ return ResourceManager.GetString("TypeNotSupported", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Operation not supported on JsonValue instances of &apos;JsonType.Default&apos; type..
+ /// </summary>
+ internal static string UseOfDefaultNotAllowed {
+ get {
+ return ResourceManager.GetString("UseOfDefaultNotAllowed", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/mcs/class/System.Json.Microsoft/System.Json/Properties/Resources.resx b/mcs/class/System.Json.Microsoft/System.Json/Properties/Resources.resx
new file mode 100644
index 00000000000..02fd621dcef
--- /dev/null
+++ b/mcs/class/System.Json.Microsoft/System.Json/Properties/Resources.resx
@@ -0,0 +1,171 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+ <!--
+ Microsoft ResX Schema
+
+ Version 2.0
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
+ associated with the data types.
+
+ Example:
+
+ ... ado.net/XML headers & schema ...
+ <resheader name="resmimetype">text/microsoft-resx</resheader>
+ <resheader name="version">2.0</resheader>
+ <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+ <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+ <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+ <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+ <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+ <value>[base64 mime encoded serialized .NET Framework object]</value>
+ </data>
+ <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+ <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+ <comment>This is a comment</comment>
+ </data>
+
+ There are any number of "resheader" rows that contain simple
+ name/value pairs.
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
+ mimetype set.
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
+ extensible. For a given mimetype the value must be set accordingly:
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
+ read any of the formats listed below.
+
+ mimetype: application/x-microsoft.net.object.binary.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.soap.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.bytearray.base64
+ value : The object must be serialized into a byte array
+ : using a System.ComponentModel.TypeConverter
+ : and then encoded with base64 encoding.
+ -->
+ <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+ <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+ <xsd:element name="root" msdata:IsDataSet="true">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded">
+ <xsd:element name="metadata">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="name" use="required" type="xsd:string" />
+ <xsd:attribute name="type" type="xsd:string" />
+ <xsd:attribute name="mimetype" type="xsd:string" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="assembly">
+ <xsd:complexType>
+ <xsd:attribute name="alias" type="xsd:string" />
+ <xsd:attribute name="name" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="data">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+ <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+ <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="resheader">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" />
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ <resheader name="resmimetype">
+ <value>text/microsoft-resx</value>
+ </resheader>
+ <resheader name="version">
+ <value>2.0</value>
+ </resheader>
+ <resheader name="reader">
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <resheader name="writer">
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <data name="ArgumentMustBeGreaterThanOrEqualTo" xml:space="preserve">
+ <value>The argument '{0}' must be greater than or equal to {1}.</value>
+ </data>
+ <data name="CannotCastJsonValue" xml:space="preserve">
+ <value>Unable to cast object of type '{0}' to type '{1}'.</value>
+ </data>
+ <data name="CannotReadAsType" xml:space="preserve">
+ <value>CannotReadAsType=Cannot read '{0}' as '{1}' type.</value>
+ </data>
+ <data name="CannotReadPrimitiveAsType" xml:space="preserve">
+ <value>Cannot read JsonPrimitive value '{0}' as '{1}'.</value>
+ </data>
+ <data name="DynamicPropertyNotDefined" xml:space="preserve">
+ <value>'{0}' does not contain a definition for property '{1}'.</value>
+ </data>
+ <data name="IncorrectJsonFormat" xml:space="preserve">
+ <value>The input source is not correctly formatted.</value>
+ </data>
+ <data name="IndexerNotSupportedOnJsonType" xml:space="preserve">
+ <value>'{0}' type indexer is not supported on JsonValue of 'JsonType.{1}' type.</value>
+ </data>
+ <data name="InvalidCastNonNullable" xml:space="preserve">
+ <value>Cannot convert null to '{0}' because it is a non-nullable value type.</value>
+ </data>
+ <data name="InvalidDateFormat" xml:space="preserve">
+ <value>Cannot cast JsonPrimitive value '{0}' as '{1}'. It is not in a valid date format.</value>
+ </data>
+ <data name="InvalidIndexType" xml:space="preserve">
+ <value>Invalid '{0}' index type; only 'System.String' and non-negative 'System.Int32' types are supported.</value>
+ </data>
+ <data name="InvalidJsonPrimitive" xml:space="preserve">
+ <value>Invalid JSON primitive: {0}.</value>
+ </data>
+ <data name="InvalidUriFormat" xml:space="preserve">
+ <value>Cannot cast '{0}' value '{1}.{2}' as a type of '{3}'. The provided string is not a valid relative or absolute '{3}'.</value>
+ </data>
+ <data name="JsonStringCannotBeEmpty" xml:space="preserve">
+ <value>An empty string cannot be parsed as JSON.</value>
+ </data>
+ <data name="NonSingleNonNullIndexNotSupported" xml:space="preserve">
+ <value>Null index or multidimensional indexing is not supported by this indexer; use 'System.Int32' or 'System.String' for array and object indexing respectively.</value>
+ </data>
+ <data name="OverflowReadAs" xml:space="preserve">
+ <value>Cannot cast JsonPrimitive value '{0}' as '{1}'. The value is either too large or too small for the specified CLR type.</value>
+ </data>
+ <data name="TypeNotSupported" xml:space="preserve">
+ <value>Object type not supported.</value>
+ </data>
+ <data name="UseOfDefaultNotAllowed" xml:space="preserve">
+ <value>Operation not supported on JsonValue instances of 'JsonType.Default' type.</value>
+ </data>
+</root> \ No newline at end of file
diff --git a/mcs/class/System.Json.Microsoft/Test/System.Json/JsonValueTest.cs b/mcs/class/System.Json.Microsoft/Test/System.Json/JsonValueTest.cs
new file mode 100644
index 00000000000..c302a515073
--- /dev/null
+++ b/mcs/class/System.Json.Microsoft/Test/System.Json/JsonValueTest.cs
@@ -0,0 +1,30 @@
+//
+// JsonValueTest.cs: Tests for JSonValue
+//
+// Copyright 2011 Xamarin, Inc.
+//
+// Authors:
+// Miguel de Icaza
+//
+using NUnit.Framework;
+using System;
+using System.IO;
+using System.Text;
+using System.Json;
+
+namespace MonoTests.System
+{
+ [TestFixture]
+ public class JsonValueTests {
+ // Tests that a trailing comma is allowed in dictionary definitions
+ // Test that we correctly serialize JsonArray with null elements.
+ [Test]
+ public void ToStringOnJsonArrayWithNulls () {
+ var j = JsonValue.Load (new StringReader ("[1,2,3,null]"));
+ Assert.AreEqual (4, j.Count, "itemcount");
+ Assert.AreEqual (JsonType.Array, j.JsonType, "type");
+ var str = j.ToString ();
+ Assert.AreEqual ("[1,2,3,null]", str);
+ }
+ }
+}