diff --git a/Src/Newtonsoft.Json.Tests/Linq/JTokenTests.cs b/Src/Newtonsoft.Json.Tests/Linq/JTokenTests.cs
index ebd327db..96bb225e 100644
--- a/Src/Newtonsoft.Json.Tests/Linq/JTokenTests.cs
+++ b/Src/Newtonsoft.Json.Tests/Linq/JTokenTests.cs
@@ -230,7 +230,7 @@ namespace Newtonsoft.Json.Tests.Linq
public void Casting()
{
Assert.AreEqual(1L, (long)(new JValue(1)));
- Assert.AreEqual(2L, (long) new JArray(1, 2, 3)[1]);
+ Assert.AreEqual(2L, (long)new JArray(1, 2, 3)[1]);
Assert.AreEqual(new DateTime(2000, 12, 20), (DateTime)new JValue(new DateTime(2000, 12, 20)));
#if !PocketPC && !NET20
@@ -261,6 +261,8 @@ namespace Newtonsoft.Json.Tests.Linq
Assert.AreEqual(null, (uint?)(JValue)null);
Assert.AreEqual(null, (sbyte?)new JValue((sbyte?)null));
Assert.AreEqual(null, (sbyte?)(JValue)null);
+ Assert.AreEqual(null, (byte?)new JValue((byte?)null));
+ Assert.AreEqual(null, (byte?)(JValue)null);
Assert.AreEqual(null, (ulong?)new JValue((ulong?)null));
Assert.AreEqual(null, (ulong?)(JValue)null);
Assert.AreEqual(null, (uint?)new JValue((uint?)null));
@@ -277,6 +279,7 @@ namespace Newtonsoft.Json.Tests.Linq
Assert.AreEqual(5f, (float)(new JValue(5L)));
Assert.AreEqual(5f, (float)(new JValue(5m)));
Assert.AreEqual(5f, (float?)(new JValue(5m)));
+ Assert.AreEqual(5, (byte)(new JValue(5)));
byte[] data = new byte[0];
Assert.AreEqual(data, (byte[])(new JValue(data)));
@@ -284,6 +287,49 @@ namespace Newtonsoft.Json.Tests.Linq
Assert.AreEqual(5, (int)(new JValue(StringComparison.OrdinalIgnoreCase)));
}
+ [Test]
+ public void ToObject()
+ {
+ Assert.AreEqual(1L, (new JValue(1).ToObject(typeof(ushort))));
+ Assert.AreEqual(1L, (new JValue(1).ToObject(typeof(ushort?))));
+ Assert.AreEqual(1L, (new JValue(1).ToObject(typeof(uint))));
+ Assert.AreEqual(1L, (new JValue(1).ToObject(typeof(uint?))));
+ Assert.AreEqual(1L, (new JValue(1).ToObject(typeof(ulong))));
+ Assert.AreEqual(1L, (new JValue(1).ToObject(typeof(ulong?))));
+ Assert.AreEqual(1L, (new JValue(1).ToObject(typeof(sbyte))));
+ Assert.AreEqual(1L, (new JValue(1).ToObject(typeof(sbyte?))));
+ Assert.AreEqual(1L, (new JValue(1).ToObject(typeof(byte))));
+ Assert.AreEqual(1L, (new JValue(1).ToObject(typeof(byte?))));
+ Assert.AreEqual(1L, (new JValue(1).ToObject(typeof(short))));
+ Assert.AreEqual(1L, (new JValue(1).ToObject(typeof(short?))));
+ Assert.AreEqual(1L, (new JValue(1).ToObject(typeof(int))));
+ Assert.AreEqual(1L, (new JValue(1).ToObject(typeof(int?))));
+ Assert.AreEqual(1L, (new JValue(1).ToObject(typeof(long))));
+ Assert.AreEqual(1L, (new JValue(1).ToObject(typeof(long?))));
+ Assert.AreEqual(1L, (new JValue(1.0).ToObject(typeof(float))));
+ Assert.AreEqual(1L, (new JValue(1.0).ToObject(typeof(float?))));
+ Assert.AreEqual(1L, (new JValue(1.0).ToObject(typeof(double))));
+ Assert.AreEqual(1L, (new JValue(1.0).ToObject(typeof(double?))));
+ Assert.AreEqual(1L, (new JValue(1).ToObject(typeof(decimal))));
+ Assert.AreEqual(1L, (new JValue(1).ToObject(typeof(decimal?))));
+ Assert.AreEqual(true, (new JValue(true).ToObject(typeof(bool))));
+ Assert.AreEqual(true, (new JValue(true).ToObject(typeof(bool?))));
+ Assert.AreEqual('b', (new JValue('b').ToObject(typeof(char))));
+ Assert.AreEqual('b', (new JValue('b').ToObject(typeof(char?))));
+ Assert.AreEqual(TimeSpan.MaxValue, (new JValue(TimeSpan.MaxValue).ToObject(typeof(TimeSpan))));
+ Assert.AreEqual(TimeSpan.MaxValue, (new JValue(TimeSpan.MaxValue).ToObject(typeof(TimeSpan?))));
+ Assert.AreEqual(DateTime.MaxValue, (new JValue(DateTime.MaxValue).ToObject(typeof(DateTime))));
+ Assert.AreEqual(DateTime.MaxValue, (new JValue(DateTime.MaxValue).ToObject(typeof(DateTime?))));
+#if !NET20
+ Assert.AreEqual(DateTimeOffset.MaxValue, (new JValue(DateTimeOffset.MaxValue).ToObject(typeof(DateTimeOffset))));
+ Assert.AreEqual(DateTimeOffset.MaxValue, (new JValue(DateTimeOffset.MaxValue).ToObject(typeof(DateTimeOffset?))));
+#endif
+ Assert.AreEqual("b", (new JValue("b").ToObject(typeof(string))));
+ Assert.AreEqual(new Guid("A34B2080-B5F0-488E-834D-45D44ECB9E5C"), (new JValue(new Guid("A34B2080-B5F0-488E-834D-45D44ECB9E5C")).ToObject(typeof(Guid))));
+ Assert.AreEqual(new Guid("A34B2080-B5F0-488E-834D-45D44ECB9E5C"), (new JValue(new Guid("A34B2080-B5F0-488E-834D-45D44ECB9E5C")).ToObject(typeof(Guid?))));
+ Assert.AreEqual(new Uri("http://www.google.com/"), (new JValue(new Uri("http://www.google.com/")).ToObject(typeof(Uri))));
+ }
+
[Test]
public void ImplicitCastingTo()
{
@@ -308,6 +354,7 @@ namespace Newtonsoft.Json.Tests.Linq
Assert.IsTrue(JToken.DeepEquals(new JValue((ulong?)null), (JValue)(ulong?)null));
Assert.IsTrue(JToken.DeepEquals(new JValue((sbyte?)null), (JValue)(sbyte?)null));
Assert.IsTrue(JToken.DeepEquals(new JValue((ushort?)null), (JValue)(ushort?)null));
+ Assert.IsTrue(JToken.DeepEquals(new JValue(short.MaxValue), (JValue)short.MaxValue));
Assert.IsTrue(JToken.DeepEquals(new JValue(ushort.MaxValue), (JValue)ushort.MaxValue));
Assert.IsTrue(JToken.DeepEquals(new JValue(11.1f), (JValue)11.1f));
Assert.IsTrue(JToken.DeepEquals(new JValue(float.MinValue), (JValue)float.MinValue));
diff --git a/Src/Newtonsoft.Json/Linq/JToken.cs b/Src/Newtonsoft.Json/Linq/JToken.cs
index 3ef15546..3301fc49 100644
--- a/Src/Newtonsoft.Json/Linq/JToken.cs
+++ b/Src/Newtonsoft.Json/Linq/JToken.cs
@@ -403,9 +403,9 @@ namespace Newtonsoft.Json.Linq
return (o.Type == JTokenType.Boolean || (nullable && IsNullable(o)));
}
- private static bool ValidateString(JToken o)
+ private static bool ValidateString(JToken o, bool nullable)
{
- return (o.Type == JTokenType.String || o.Type == JTokenType.Comment || o.Type == JTokenType.Raw || IsNullable(o));
+ return (o.Type == JTokenType.String || o.Type == JTokenType.Comment || o.Type == JTokenType.Raw || (nullable && IsNullable(o)));
}
private static bool ValidateBytes(JToken o)
@@ -542,7 +542,24 @@ namespace Newtonsoft.Json.Linq
if (v == null || !ValidateFloat(v, true))
throw new ArgumentException("Can not convert {0} to Double.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
- return (double?)v.Value;
+ return (v.Value != null) ? (double?)Convert.ToDouble(v.Value, CultureInfo.InvariantCulture) : null;
+ }
+
+ ///
+ /// Performs an explicit conversion from to .
+ ///
+ /// The value.
+ /// The result of the conversion.
+ public static explicit operator char?(JToken value)
+ {
+ if (value == null)
+ return null;
+
+ JValue v = EnsureValue(value);
+ if (v == null || !ValidateString(v, true))
+ throw new ArgumentException("Can not convert {0} to Char.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
+
+ return (v.Value != null) ? (char?)Convert.ToChar(v.Value, CultureInfo.InvariantCulture) : null;
}
///
@@ -588,6 +605,35 @@ namespace Newtonsoft.Json.Linq
return Convert.ToUInt16(v.Value, CultureInfo.InvariantCulture);
}
+ ///
+ /// Performs an explicit conversion from to .
+ ///
+ /// The value.
+ /// The result of the conversion.
+ [CLSCompliant(false)]
+ public static explicit operator char(JToken value)
+ {
+ JValue v = EnsureValue(value);
+ if (v == null || (!ValidateInteger(v, false) && !ValidateString(v, false)))
+ throw new ArgumentException("Can not convert {0} to Char.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
+
+ return Convert.ToChar(v.Value, CultureInfo.InvariantCulture);
+ }
+
+ ///
+ /// Performs an explicit conversion from to .
+ ///
+ /// The value.
+ /// The result of the conversion.
+ public static explicit operator byte(JToken value)
+ {
+ JValue v = EnsureValue(value);
+ if (v == null || !ValidateInteger(v, false))
+ throw new ArgumentException("Can not convert {0} to Byte.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
+
+ return Convert.ToByte(v.Value, CultureInfo.InvariantCulture);
+ }
+
///
/// Performs an explicit conversion from to .
///
@@ -637,7 +683,24 @@ namespace Newtonsoft.Json.Linq
if (v == null || !ValidateInteger(v, true))
throw new ArgumentException("Can not convert {0} to UInt16.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
- return (v.Value != null) ? (ushort?)Convert.ToInt16(v.Value, CultureInfo.InvariantCulture) : null;
+ return (v.Value != null) ? (ushort?)Convert.ToUInt16(v.Value, CultureInfo.InvariantCulture) : null;
+ }
+
+ ///
+ /// Performs an explicit conversion from to .
+ ///
+ /// The value.
+ /// The result of the conversion.
+ public static explicit operator byte?(JToken value)
+ {
+ if (value == null)
+ return null;
+
+ JValue v = EnsureValue(value);
+ if (v == null || !ValidateInteger(v, true))
+ throw new ArgumentException("Can not convert {0} to Byte.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
+
+ return (v.Value != null) ? (byte?)Convert.ToByte(v.Value, CultureInfo.InvariantCulture) : null;
}
///
@@ -777,7 +840,7 @@ namespace Newtonsoft.Json.Linq
return null;
JValue v = EnsureValue(value);
- if (v == null || !ValidateString(v))
+ if (v == null || !ValidateString(v, true))
throw new ArgumentException("Can not convert {0} to String.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
return (v.Value != null) ? Convert.ToString(v.Value, CultureInfo.InvariantCulture) : null;
@@ -826,6 +889,85 @@ namespace Newtonsoft.Json.Linq
return (byte[])v.Value;
}
+
+ ///
+ /// Performs an explicit conversion from to .
+ ///
+ /// The value.
+ /// The result of the conversion.
+ public static explicit operator Guid(JToken value)
+ {
+ JValue v = EnsureValue(value);
+ if (v == null || !ValidateString(v, false))
+ throw new ArgumentException("Can not convert {0} to Guid.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
+
+ return (v.Value is Guid) ? (Guid)v.Value : new Guid((string)v.Value);
+ }
+
+ ///
+ /// Performs an explicit conversion from to .
+ ///
+ /// The value.
+ /// The result of the conversion.
+ public static explicit operator Guid?(JToken value)
+ {
+ JValue v = EnsureValue(value);
+ if (v == null || !ValidateString(v, true))
+ throw new ArgumentException("Can not convert {0} to Guid.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
+
+ if (v.Value == null)
+ return null;
+
+ return (v.Value is Guid) ? (Guid)v.Value : new Guid(Convert.ToString(v.Value, CultureInfo.InvariantCulture));
+ }
+
+ ///
+ /// Performs an explicit conversion from to .
+ ///
+ /// The value.
+ /// The result of the conversion.
+ public static explicit operator TimeSpan(JToken value)
+ {
+ JValue v = EnsureValue(value);
+ if (v == null || !ValidateString(v, false))
+ throw new ArgumentException("Can not convert {0} to TimeSpan.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
+
+ return (v.Value is TimeSpan) ? (TimeSpan)v.Value : ConvertUtils.ParseTimeSpan(Convert.ToString(v.Value, CultureInfo.InvariantCulture));
+ }
+
+ ///
+ /// Performs an explicit conversion from to .
+ ///
+ /// The value.
+ /// The result of the conversion.
+ public static explicit operator TimeSpan?(JToken value)
+ {
+ JValue v = EnsureValue(value);
+ if (v == null || !ValidateString(v, true))
+ throw new ArgumentException("Can not convert {0} to TimeSpan.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
+
+ if (v.Value == null)
+ return null;
+
+ return (v.Value is TimeSpan) ? (TimeSpan)v.Value : ConvertUtils.ParseTimeSpan(Convert.ToString(v.Value, CultureInfo.InvariantCulture));
+ }
+
+ ///
+ /// Performs an explicit conversion from to .
+ ///
+ /// The value.
+ /// The result of the conversion.
+ public static explicit operator Uri(JToken value)
+ {
+ JValue v = EnsureValue(value);
+ if (v == null || !ValidateString(v, true))
+ throw new ArgumentException("Can not convert {0} to Uri.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
+
+ if (v.Value == null)
+ return null;
+
+ return (v.Value is Uri) ? (Uri)v.Value : new Uri(Convert.ToString(v.Value, CultureInfo.InvariantCulture));
+ }
#endregion
#region Cast to operators
@@ -1171,7 +1313,134 @@ namespace Newtonsoft.Json.Linq
/// The new object created from the JSON value.
public T ToObject()
{
- return ToObject(new JsonSerializer());
+ return (T)ToObject(typeof(T));
+ }
+
+ ///
+ /// Creates the specified .NET type from the .
+ ///
+ /// The object type that the token will be deserialized to.
+ /// The new object created from the JSON value.
+ public object ToObject(Type objectType)
+ {
+ return ToObject(objectType, false);
+ }
+
+ private object ToObject(Type objectType, bool isNullable)
+ {
+ TypeCode typeCode = ConvertUtils.GetTypeCode(objectType);
+
+ switch (typeCode)
+ {
+ case TypeCode.Object:
+ if (!isNullable && ReflectionUtils.IsNullableType(objectType))
+ return ToObject(Nullable.GetUnderlyingType(objectType), true);
+
+ // fall back to standard JsonSerializer
+ break;
+ case TypeCode.Boolean:
+ if (isNullable)
+ return (bool?) this;
+
+ return (bool) this;
+ case TypeCode.Char:
+ if (isNullable)
+ return (char?) this;
+
+ return (char) this;
+ case TypeCode.SByte:
+ if (isNullable)
+ return (sbyte?) this;
+
+ return (sbyte) this;
+ case TypeCode.Byte:
+ if (isNullable)
+ return (byte?) this;
+
+ return (byte) this;
+ case TypeCode.Int16:
+ if (isNullable)
+ return (short?) this;
+
+ return (short) this;
+ case TypeCode.UInt16:
+ if (isNullable)
+ return (ushort?) this;
+
+ return (ushort) this;
+ case TypeCode.Int32:
+ if (isNullable)
+ return (int?) this;
+
+ return (int) this;
+ case TypeCode.UInt32:
+ if (isNullable)
+ return (uint?) this;
+
+ return (uint) this;
+ case TypeCode.Int64:
+ if (isNullable)
+ return (long?) this;
+
+ return (long) this;
+ case TypeCode.UInt64:
+ if (isNullable)
+ return (ulong?) this;
+
+ return (ulong) this;
+ case TypeCode.Single:
+ if (isNullable)
+ return (float?) this;
+
+ return (float) this;
+ case TypeCode.Double:
+ if (isNullable)
+ return (double?) this;
+
+ return (double) this;
+ case TypeCode.Decimal:
+ if (isNullable)
+ return (decimal?) this;
+
+ return (decimal) this;
+ case TypeCode.DateTime:
+ if (isNullable)
+ return (DateTime?) this;
+
+ return (DateTime) this;
+ case TypeCode.String:
+ return (string) this;
+ }
+
+#if !PocketPC && !NET20
+ if (objectType == typeof (DateTimeOffset))
+ {
+ if (isNullable)
+ return (DateTimeOffset?) this;
+
+ return (DateTimeOffset) this;
+ }
+#endif
+ if (objectType == typeof (Guid))
+ {
+ if (isNullable)
+ return (Guid?) this;
+
+ return (Guid) this;
+ }
+ if (objectType == typeof (Uri))
+ {
+ return (Uri) this;
+ }
+ if (objectType == typeof (TimeSpan))
+ {
+ if (isNullable)
+ return (TimeSpan?) this;
+
+ return (TimeSpan) this;
+ }
+
+ return ToObject(objectType, new JsonSerializer());
}
///
@@ -1181,12 +1450,23 @@ namespace Newtonsoft.Json.Linq
/// The that will be used when creating the object.
/// The new object created from the JSON value.
public T ToObject(JsonSerializer jsonSerializer)
+ {
+ return (T)ToObject(typeof(T), jsonSerializer);
+ }
+
+ ///
+ /// Creates the specified .NET type from the using the specified .
+ ///
+ /// The object type that the token will be deserialized to.
+ /// The that will be used when creating the object.
+ /// The new object created from the JSON value.
+ public object ToObject(Type objectType, JsonSerializer jsonSerializer)
{
ValidationUtils.ArgumentNotNull(jsonSerializer, "jsonSerializer");
using (JTokenReader jsonReader = new JTokenReader(this))
{
- return jsonSerializer.Deserialize(jsonReader);
+ return jsonSerializer.Deserialize(jsonReader, objectType);
}
}
diff --git a/Src/Newtonsoft.Json/Linq/JValue.cs b/Src/Newtonsoft.Json/Linq/JValue.cs
index 95c41cfc..d9218b05 100644
--- a/Src/Newtonsoft.Json/Linq/JValue.cs
+++ b/Src/Newtonsoft.Json/Linq/JValue.cs
@@ -66,6 +66,15 @@ namespace Newtonsoft.Json.Linq
{
}
+ ///
+ /// Initializes a new instance of the class with the given value.
+ ///
+ /// The value.
+ public JValue(char value)
+ : this(value, JTokenType.String)
+ {
+ }
+
///
/// Initializes a new instance of the class with the given value.
///
diff --git a/Src/Newtonsoft.Json/Serialization/MemoryTraceWriter.cs b/Src/Newtonsoft.Json/Serialization/MemoryTraceWriter.cs
index 7b639db5..0d40ea5a 100644
--- a/Src/Newtonsoft.Json/Serialization/MemoryTraceWriter.cs
+++ b/Src/Newtonsoft.Json/Serialization/MemoryTraceWriter.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
+using System.Globalization;
using System.Text;
namespace Newtonsoft.Json.Serialization
@@ -40,7 +41,7 @@ namespace Newtonsoft.Json.Serialization
/// The trace exception. This parameter is optional.
public void Trace(TraceLevel level, string message, Exception ex)
{
- string traceMessage = DateTime.Now.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff") + " " + level.ToString("g") + " " + message;
+ string traceMessage = DateTime.Now.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff", CultureInfo.InvariantCulture) + " " + level.ToString("g") + " " + message;
if (_traceMessages.Count >= 1000)
_traceMessages.Dequeue();
diff --git a/Src/Newtonsoft.Json/Utilities/ConvertUtils.cs b/Src/Newtonsoft.Json/Utilities/ConvertUtils.cs
index b8de27bc..13c89f9d 100644
--- a/Src/Newtonsoft.Json/Utilities/ConvertUtils.cs
+++ b/Src/Newtonsoft.Json/Utilities/ConvertUtils.cs
@@ -222,6 +222,15 @@ namespace Newtonsoft.Json.Utilities
#endif
}
+ public static TimeSpan ParseTimeSpan(string input)
+ {
+#if !(NET35 || NET20 || PORTABLE || WINDOWS_PHONE)
+ return TimeSpan.Parse((string) input, CultureInfo.InvariantCulture);
+#else
+ return TimeSpan.Parse((string)input);
+#endif
+ }
+
internal struct TypeConvertKey : IEquatable
{
private readonly Type _initialType;
@@ -331,12 +340,8 @@ namespace Newtonsoft.Json.Utilities
return new Guid((string) initialValue);
if (targetType == typeof (Uri))
return new Uri((string) initialValue, UriKind.RelativeOrAbsolute);
- if (targetType == typeof (TimeSpan))
-#if !(NET35 || NET20 || PORTABLE || WINDOWS_PHONE)
- return TimeSpan.Parse((string) initialValue, CultureInfo.InvariantCulture);
-#else
- return TimeSpan.Parse((string)initialValue);
-#endif
+ if (targetType == typeof(TimeSpan))
+ return ParseTimeSpan((string) initialValue);
}
#if !(NETFX_CORE || PORTABLE)