-Added non-generic JToken.ToObject methods

-Added byte, char, Guid, TimeSpan and Uri explicit conversion operators to JToken
-Fixed globalization warnings
This commit is contained in:
James Newton-King
2012-11-18 21:10:01 +13:00
parent e3be3e43db
commit a8249e38df
5 changed files with 357 additions and 15 deletions
+48 -1
View File
@@ -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));
+287 -7
View File
@@ -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;
}
/// <summary>
/// Performs an explicit conversion from <see cref="Newtonsoft.Json.Linq.JToken"/> to <see cref="Nullable{Char}"/>.
/// </summary>
/// <param name="value">The value.</param>
/// <returns>The result of the conversion.</returns>
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;
}
/// <summary>
@@ -588,6 +605,35 @@ namespace Newtonsoft.Json.Linq
return Convert.ToUInt16(v.Value, CultureInfo.InvariantCulture);
}
/// <summary>
/// Performs an explicit conversion from <see cref="Newtonsoft.Json.Linq.JToken"/> to <see cref="System.Char"/>.
/// </summary>
/// <param name="value">The value.</param>
/// <returns>The result of the conversion.</returns>
[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);
}
/// <summary>
/// Performs an explicit conversion from <see cref="Newtonsoft.Json.Linq.JToken"/> to <see cref="System.Byte"/>.
/// </summary>
/// <param name="value">The value.</param>
/// <returns>The result of the conversion.</returns>
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);
}
/// <summary>
/// Performs an explicit conversion from <see cref="Newtonsoft.Json.Linq.JToken"/> to <see cref="Nullable{Int32}"/>.
/// </summary>
@@ -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;
}
/// <summary>
/// Performs an explicit conversion from <see cref="Newtonsoft.Json.Linq.JToken"/> to <see cref="Nullable{Byte}"/>.
/// </summary>
/// <param name="value">The value.</param>
/// <returns>The result of the conversion.</returns>
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;
}
/// <summary>
@@ -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;
}
/// <summary>
/// Performs an explicit conversion from <see cref="Newtonsoft.Json.Linq.JToken"/> to <see cref="System.Guid"/>.
/// </summary>
/// <param name="value">The value.</param>
/// <returns>The result of the conversion.</returns>
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);
}
/// <summary>
/// Performs an explicit conversion from <see cref="Newtonsoft.Json.Linq.JToken"/> to <see cref="System.Guid"/>.
/// </summary>
/// <param name="value">The value.</param>
/// <returns>The result of the conversion.</returns>
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));
}
/// <summary>
/// Performs an explicit conversion from <see cref="Newtonsoft.Json.Linq.JToken"/> to <see cref="System.TimeSpan"/>.
/// </summary>
/// <param name="value">The value.</param>
/// <returns>The result of the conversion.</returns>
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));
}
/// <summary>
/// Performs an explicit conversion from <see cref="Newtonsoft.Json.Linq.JToken"/> to <see cref="System.TimeSpan"/>.
/// </summary>
/// <param name="value">The value.</param>
/// <returns>The result of the conversion.</returns>
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));
}
/// <summary>
/// Performs an explicit conversion from <see cref="Newtonsoft.Json.Linq.JToken"/> to <see cref="System.Uri"/>.
/// </summary>
/// <param name="value">The value.</param>
/// <returns>The result of the conversion.</returns>
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
/// <returns>The new object created from the JSON value.</returns>
public T ToObject<T>()
{
return ToObject<T>(new JsonSerializer());
return (T)ToObject(typeof(T));
}
/// <summary>
/// Creates the specified .NET type from the <see cref="JToken"/>.
/// </summary>
/// <param name="objectType">The object type that the token will be deserialized to.</param>
/// <returns>The new object created from the JSON value.</returns>
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());
}
/// <summary>
@@ -1181,12 +1450,23 @@ namespace Newtonsoft.Json.Linq
/// <param name="jsonSerializer">The <see cref="JsonSerializer"/> that will be used when creating the object.</param>
/// <returns>The new object created from the JSON value.</returns>
public T ToObject<T>(JsonSerializer jsonSerializer)
{
return (T)ToObject(typeof(T), jsonSerializer);
}
/// <summary>
/// Creates the specified .NET type from the <see cref="JToken"/> using the specified <see cref="JsonSerializer"/>.
/// </summary>
/// <param name="objectType">The object type that the token will be deserialized to.</param>
/// <param name="jsonSerializer">The <see cref="JsonSerializer"/> that will be used when creating the object.</param>
/// <returns>The new object created from the JSON value.</returns>
public object ToObject(Type objectType, JsonSerializer jsonSerializer)
{
ValidationUtils.ArgumentNotNull(jsonSerializer, "jsonSerializer");
using (JTokenReader jsonReader = new JTokenReader(this))
{
return jsonSerializer.Deserialize<T>(jsonReader);
return jsonSerializer.Deserialize(jsonReader, objectType);
}
}
+9
View File
@@ -66,6 +66,15 @@ namespace Newtonsoft.Json.Linq
{
}
/// <summary>
/// Initializes a new instance of the <see cref="JValue"/> class with the given value.
/// </summary>
/// <param name="value">The value.</param>
public JValue(char value)
: this(value, JTokenType.String)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="JValue"/> class with the given value.
/// </summary>
@@ -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
/// <param name="ex">The trace exception. This parameter is optional.</param>
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();
+11 -6
View File
@@ -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<TypeConvertKey>
{
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)