-Added support for serializing custom IConvertible values

-Refactored away dependency on IConvertible
This commit is contained in:
James Newton-King
2013-04-01 12:38:45 +13:00
parent 08c7055d91
commit b5e7005735
17 changed files with 704 additions and 957 deletions
@@ -63,6 +63,16 @@ namespace Newtonsoft.Json.Tests
writer.Close();
Assert.IsTrue(ms.CanRead);
}
[Test]
public void WriteIConvertable()
{
var sw = new StringWriter();
JsonTextWriter writer = new JsonTextWriter(sw);
writer.WriteValue(new ConvertibleInt(1));
Assert.AreEqual("1", sw.ToString());
}
[Test]
public void ValueFormatting()
@@ -1260,7 +1270,103 @@ _____'propertyName': NaN
if (appendDelimiters)
writer.Write(delimiter);
}
}
public struct ConvertibleInt : IConvertible
{
private readonly int _value;
public ConvertibleInt(int value)
{
_value = value;
}
public TypeCode GetTypeCode()
{
return TypeCode.Int32;
}
public bool ToBoolean(IFormatProvider provider)
{
throw new NotImplementedException();
}
public byte ToByte(IFormatProvider provider)
{
throw new NotImplementedException();
}
public char ToChar(IFormatProvider provider)
{
throw new NotImplementedException();
}
public DateTime ToDateTime(IFormatProvider provider)
{
throw new NotImplementedException();
}
public decimal ToDecimal(IFormatProvider provider)
{
throw new NotImplementedException();
}
public double ToDouble(IFormatProvider provider)
{
throw new NotImplementedException();
}
public short ToInt16(IFormatProvider provider)
{
throw new NotImplementedException();
}
public int ToInt32(IFormatProvider provider)
{
throw new NotImplementedException();
}
public long ToInt64(IFormatProvider provider)
{
throw new NotImplementedException();
}
public sbyte ToSByte(IFormatProvider provider)
{
throw new NotImplementedException();
}
public float ToSingle(IFormatProvider provider)
{
throw new NotImplementedException();
}
public string ToString(IFormatProvider provider)
{
throw new NotImplementedException();
}
public object ToType(Type conversionType, IFormatProvider provider)
{
if (conversionType == typeof(int))
return _value;
throw new Exception("Type not supported: " + conversionType.FullName);
}
public ushort ToUInt16(IFormatProvider provider)
{
throw new NotImplementedException();
}
public uint ToUInt32(IFormatProvider provider)
{
throw new NotImplementedException();
}
public ulong ToUInt64(IFormatProvider provider)
{
throw new NotImplementedException();
}
}
}
@@ -100,7 +100,7 @@ namespace Newtonsoft.Json.Tests
DataContractJsonSerializer
}
#endregion
#endregion
[Test]
public void SerializeSimpleObject()
@@ -5762,6 +5762,46 @@ To fix this error either change the environment to be fully trusted, change the
});
}
public class ConvertableIntTestClass
{
public ConvertibleInt Integer { get; set; }
public ConvertibleInt? NullableInteger1 { get; set; }
public ConvertibleInt? NullableInteger2 { get; set; }
}
[Test]
public void SerializeIConvertible()
{
ConvertableIntTestClass c = new ConvertableIntTestClass
{
Integer = new ConvertibleInt(1),
NullableInteger1 = new ConvertibleInt(2),
NullableInteger2 = null
};
string json = JsonConvert.SerializeObject(c, Formatting.Indented);
Assert.AreEqual(@"{
""Integer"": 1,
""NullableInteger1"": 2,
""NullableInteger2"": null
}", json);
}
[Test]
public void DeserializeIConvertible()
{
string json = @"{
""Integer"": 1,
""NullableInteger1"": 2,
""NullableInteger2"": null
}";
ExceptionAssert.Throws<JsonSerializationException>(
"Error converting value 1 to type 'Newtonsoft.Json.Tests.ConvertibleInt'. Path 'Integer', line 2, position 15.",
() => JsonConvert.DeserializeObject<ConvertableIntTestClass>(json));
}
[Test]
public void SerializeNullableWidgetStruct()
{
@@ -6352,7 +6392,7 @@ Parameter name: value",
[Test]
public void DateTimeDictionaryKey_DateTimeOffset_MS()
{
IDictionary<DateTimeOffset, int> dic1 = new Dictionary<DateTimeOffset, int>
IDictionary<DateTimeOffset?, int> dic1 = new Dictionary<DateTimeOffset?, int>
{
{new DateTimeOffset(2000, 12, 12, 12, 12, 12, TimeSpan.Zero), 1},
{new DateTimeOffset(2013, 12, 12, 12, 12, 12, TimeSpan.Zero), 2}
@@ -6368,7 +6408,7 @@ Parameter name: value",
""\/Date(1386850332000+0000)\/"": 2
}", json);
IDictionary<DateTimeOffset, int> dic2 = JsonConvert.DeserializeObject<IDictionary<DateTimeOffset, int>>(json);
IDictionary<DateTimeOffset?, int> dic2 = JsonConvert.DeserializeObject<IDictionary<DateTimeOffset?, int>>(json);
Assert.AreEqual(2, dic2.Count);
Assert.AreEqual(1, dic2[new DateTimeOffset(2000, 12, 12, 12, 12, 12, TimeSpan.Zero)]);
@@ -70,6 +70,7 @@ namespace Newtonsoft.Json.Converters
if (char.IsNumber(enumName[0]) || enumName[0] == '-')
{
// enum value has no name so write number
writer.WriteValue(value);
}
else
+56 -108
View File
@@ -32,6 +32,7 @@ using System.Numerics;
#if !(NET20 || NET35 || SILVERLIGHT)
using System.Threading.Tasks;
#endif
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Utilities;
using System.Xml;
using Newtonsoft.Json.Converters;
@@ -39,9 +40,6 @@ using System.Text;
#if !NET20 && (!SILVERLIGHT || WINDOWS_PHONE)
using System.Xml.Linq;
#endif
#if NETFX_CORE || PORTABLE
using IConvertible = Newtonsoft.Json.Utilities.Convertible;
#endif
namespace Newtonsoft.Json
{
@@ -625,127 +623,77 @@ namespace Newtonsoft.Json
if (value == null)
return Null;
IConvertible convertible = ConvertUtils.ToConvertible(value);
PrimitiveTypeCode typeCode = ConvertUtils.GetTypeCode(value);
if (convertible != null)
switch (typeCode)
{
switch (convertible.GetTypeCode())
{
case TypeCode.String:
return ToString(convertible.ToString(CultureInfo.InvariantCulture));
case TypeCode.Char:
return ToString(convertible.ToChar(CultureInfo.InvariantCulture));
case TypeCode.Boolean:
return ToString(convertible.ToBoolean(CultureInfo.InvariantCulture));
case TypeCode.SByte:
return ToString(convertible.ToSByte(CultureInfo.InvariantCulture));
case TypeCode.Int16:
return ToString(convertible.ToInt16(CultureInfo.InvariantCulture));
case TypeCode.UInt16:
return ToString(convertible.ToUInt16(CultureInfo.InvariantCulture));
case TypeCode.Int32:
return ToString(convertible.ToInt32(CultureInfo.InvariantCulture));
case TypeCode.Byte:
return ToString(convertible.ToByte(CultureInfo.InvariantCulture));
case TypeCode.UInt32:
return ToString(convertible.ToUInt32(CultureInfo.InvariantCulture));
case TypeCode.Int64:
return ToString(convertible.ToInt64(CultureInfo.InvariantCulture));
case TypeCode.UInt64:
return ToString(convertible.ToUInt64(CultureInfo.InvariantCulture));
case TypeCode.Single:
return ToString(convertible.ToSingle(CultureInfo.InvariantCulture));
case TypeCode.Double:
return ToString(convertible.ToDouble(CultureInfo.InvariantCulture));
case TypeCode.DateTime:
return ToString(convertible.ToDateTime(CultureInfo.InvariantCulture));
case TypeCode.Decimal:
return ToString(convertible.ToDecimal(CultureInfo.InvariantCulture));
case PrimitiveTypeCode.String:
return ToString((string) value);
case PrimitiveTypeCode.Char:
return ToString((char) value);
case PrimitiveTypeCode.Boolean:
return ToString((bool) value);
case PrimitiveTypeCode.SByte:
return ToString((sbyte) value);
case PrimitiveTypeCode.Int16:
return ToString((short) value);
case PrimitiveTypeCode.UInt16:
return ToString((ushort) value);
case PrimitiveTypeCode.Int32:
return ToString((int) value);
case PrimitiveTypeCode.Byte:
return ToString((byte) value);
case PrimitiveTypeCode.UInt32:
return ToString((uint) value);
case PrimitiveTypeCode.Int64:
return ToString((long) value);
case PrimitiveTypeCode.UInt64:
return ToString((ulong) value);
case PrimitiveTypeCode.Single:
return ToString((float) value);
case PrimitiveTypeCode.Double:
return ToString((double) value);
case PrimitiveTypeCode.DateTime:
return ToString((DateTime) value);
case PrimitiveTypeCode.Decimal:
return ToString((decimal) value);
#if !(NETFX_CORE || PORTABLE)
case TypeCode.DBNull:
return Null;
case PrimitiveTypeCode.DBNull:
return Null;
#endif
}
}
#if !NET20
else if (value is DateTimeOffset)
{
return ToString((DateTimeOffset) value);
}
case PrimitiveTypeCode.DateTimeOffset:
return ToString((DateTimeOffset) value);
#endif
else if (value is Guid)
{
return ToString((Guid) value);
}
else if (value is Uri)
{
return ToString((Uri) value);
}
else if (value is TimeSpan)
{
return ToString((TimeSpan) value);
}
case PrimitiveTypeCode.Guid:
return ToString((Guid) value);
case PrimitiveTypeCode.Uri:
return ToString((Uri) value);
case PrimitiveTypeCode.TimeSpan:
return ToString((TimeSpan) value);
#if !(NET20 || NET35 || SILVERLIGHT || PORTABLE)
else if (value is BigInteger)
{
return ToString((BigInteger) value);
}
case PrimitiveTypeCode.BigInteger:
return ToString((BigInteger) value);
#endif
}
throw new ArgumentException("Unsupported type: {0}. Use the JsonSerializer class to get the object's JSON representation.".FormatWith(CultureInfo.InvariantCulture, value.GetType()));
}
private static bool IsJsonPrimitiveTypeCode(TypeCode typeCode)
internal static bool IsJsonPrimitiveType(Type t)
{
switch (typeCode)
PrimitiveTypeCode typeCode = ConvertUtils.GetTypeCode(t);
if (typeCode != PrimitiveTypeCode.Empty && typeCode != PrimitiveTypeCode.Object)
return true;
if (typeof(IConvertible).IsAssignableFrom(t)
|| (ReflectionUtils.IsNullableType(t) && typeof(IConvertible).IsAssignableFrom(Nullable.GetUnderlyingType(t))))
{
case TypeCode.String:
case TypeCode.Char:
case TypeCode.Boolean:
case TypeCode.SByte:
case TypeCode.Int16:
case TypeCode.UInt16:
case TypeCode.Int32:
case TypeCode.Byte:
case TypeCode.UInt32:
case TypeCode.Int64:
case TypeCode.UInt64:
case TypeCode.Single:
case TypeCode.Double:
case TypeCode.DateTime:
case TypeCode.Decimal:
#if !(NETFX_CORE || PORTABLE)
case TypeCode.DBNull:
#endif
return true;
default:
return false;
return !typeof(JToken).IsAssignableFrom(t);
}
}
internal static bool IsJsonPrimitiveType(Type type)
{
if (ReflectionUtils.IsNullableType(type))
type = Nullable.GetUnderlyingType(type);
#if !NET20
if (type == typeof (DateTimeOffset))
return true;
#endif
if (type == typeof (byte[]))
return true;
if (type == typeof (Uri))
return true;
if (type == typeof (TimeSpan))
return true;
if (type == typeof (Guid))
return true;
#if !(NET20 || NET35 || SILVERLIGHT || PORTABLE)
if (type == typeof (BigInteger))
return true;
#endif
return IsJsonPrimitiveTypeCode(ConvertUtils.GetTypeCode(type));
return false;
}
internal static bool TryParseDateTime(string s, DateParseHandling dateParseHandling, DateTimeZoneHandling dateTimeZoneHandling, out object dt)
+1 -3
View File
@@ -621,9 +621,7 @@ namespace Newtonsoft.Json
if (Value != null)
{
string s;
if (ConvertUtils.IsConvertible(Value))
s = ConvertUtils.ToConvertible(Value).ToString(Culture);
else if (Value is IFormattable)
if (Value is IFormattable)
s = ((IFormattable)Value).ToString(null, Culture);
else
s = Value.ToString();
+18 -10
View File
@@ -47,6 +47,7 @@ namespace Newtonsoft.Json
private int _indentation;
private char _quoteChar;
private bool _quoteName;
private bool[] _charEscapeFlags;
private Base64Encoder Base64Encoder
{
@@ -86,6 +87,7 @@ namespace Newtonsoft.Json
throw new ArgumentException(@"Invalid JavaScript string quote character. Valid quote characters are ' and "".");
_quoteChar = value;
UpdateCharEscapeFlags();
}
}
@@ -121,6 +123,8 @@ namespace Newtonsoft.Json
_quoteName = true;
_indentChar = ' ';
_indentation = 2;
UpdateCharEscapeFlags();
}
/// <summary>
@@ -209,7 +213,7 @@ namespace Newtonsoft.Json
{
InternalWritePropertyName(name);
JavaScriptUtils.WriteEscapedJavaScriptString(_writer, name, _quoteChar, _quoteName, GetCharEscapeFlags(), StringEscapeHandling);
JavaScriptUtils.WriteEscapedJavaScriptString(_writer, name, _quoteChar, _quoteName, _charEscapeFlags, StringEscapeHandling);
_writer.Write(':');
}
@@ -225,7 +229,7 @@ namespace Newtonsoft.Json
if (escape)
{
JavaScriptUtils.WriteEscapedJavaScriptString(_writer, name, _quoteChar, _quoteName, GetCharEscapeFlags(), StringEscapeHandling);
JavaScriptUtils.WriteEscapedJavaScriptString(_writer, name, _quoteChar, _quoteName, _charEscapeFlags, StringEscapeHandling);
}
else
{
@@ -241,15 +245,19 @@ namespace Newtonsoft.Json
_writer.Write(':');
}
private bool[] GetCharEscapeFlags()
internal override void OnStringEscapeHandlingChanged()
{
UpdateCharEscapeFlags();
}
private void UpdateCharEscapeFlags()
{
if (StringEscapeHandling == StringEscapeHandling.EscapeHtml)
return JavaScriptUtils.HtmlCharEscapeFlags;
if (_quoteChar == '"')
return JavaScriptUtils.DoubleQuoteCharEscapeFlags;
return JavaScriptUtils.SingleQuoteCharEscapeFlags;
_charEscapeFlags = JavaScriptUtils.HtmlCharEscapeFlags;
else if (_quoteChar == '"')
_charEscapeFlags = JavaScriptUtils.DoubleQuoteCharEscapeFlags;
else
_charEscapeFlags = JavaScriptUtils.SingleQuoteCharEscapeFlags;
}
/// <summary>
@@ -335,7 +343,7 @@ namespace Newtonsoft.Json
if (value == null)
WriteValueInternal(JsonConvert.Null, JsonToken.Null);
else
JavaScriptUtils.WriteEscapedJavaScriptString(_writer, value, _quoteChar, true, GetCharEscapeFlags(), StringEscapeHandling);
JavaScriptUtils.WriteEscapedJavaScriptString(_writer, value, _quoteChar, true, _charEscapeFlags, StringEscapeHandling);
}
/// <summary>
+163 -171
View File
@@ -31,9 +31,6 @@ using System.Numerics;
#endif
using Newtonsoft.Json.Utilities;
using System.Globalization;
#if NETFX_CORE || PORTABLE
using IConvertible = Newtonsoft.Json.Utilities.Convertible;
#endif
#if NET20
using Newtonsoft.Json.Utilities.LinqBridge;
#else
@@ -250,7 +247,16 @@ namespace Newtonsoft.Json
public StringEscapeHandling StringEscapeHandling
{
get { return _stringEscapeHandling; }
set { _stringEscapeHandling = value; }
set
{
_stringEscapeHandling = value;
OnStringEscapeHandlingChanged();
}
}
internal virtual void OnStringEscapeHandlingChanged()
{
// hacky but there is a calculated value that relies on StringEscapeHandling
}
/// <summary>
@@ -1254,176 +1260,11 @@ namespace Newtonsoft.Json
/// </summary>
/// <param name="value">The <see cref="Object"/> value to write.</param>
public virtual void WriteValue(object value)
{
WriteValueInternal(value, false);
}
/// <summary>
/// Writes a <see cref="Object"/> value.
/// An error will raised if the value cannot be written as a single JSON token.
/// </summary>
/// <param name="value">The <see cref="Object"/> value to write.</param>
/// <param name="nullable">A flag indicating whether the value is nullable.</param>
public virtual void WriteValue(object value, bool nullable)
{
WriteValueInternal(value, nullable);
}
private void WriteValueInternal(object value, bool nullable)
{
if (value == null)
{
WriteNull();
return;
}
IConvertible convertible = ConvertUtils.ToConvertible(value);
if (convertible != null)
{
switch (convertible.GetTypeCode())
{
case TypeCode.String:
WriteValue(convertible.ToString(CultureInfo.InvariantCulture));
return;
case TypeCode.Char:
if (nullable)
WriteValue((char?)convertible.ToChar(CultureInfo.InvariantCulture));
else
WriteValue(convertible.ToChar(CultureInfo.InvariantCulture));
return;
case TypeCode.Boolean:
if (nullable)
WriteValue((bool?)convertible.ToBoolean(CultureInfo.InvariantCulture));
else
WriteValue(convertible.ToBoolean(CultureInfo.InvariantCulture));
return;
case TypeCode.SByte:
if (nullable)
WriteValue((sbyte?)convertible.ToSByte(CultureInfo.InvariantCulture));
else
WriteValue(convertible.ToSByte(CultureInfo.InvariantCulture));
return;
case TypeCode.Int16:
if (nullable)
WriteValue((short?)convertible.ToInt16(CultureInfo.InvariantCulture));
else
WriteValue(convertible.ToInt16(CultureInfo.InvariantCulture));
return;
case TypeCode.UInt16:
if (nullable)
WriteValue((ushort?)convertible.ToUInt16(CultureInfo.InvariantCulture));
else
WriteValue(convertible.ToUInt16(CultureInfo.InvariantCulture));
return;
case TypeCode.Int32:
if (nullable)
WriteValue((int?)convertible.ToInt32(CultureInfo.InvariantCulture));
else
WriteValue(convertible.ToInt32(CultureInfo.InvariantCulture));
return;
case TypeCode.Byte:
if (nullable)
WriteValue((byte?)convertible.ToByte(CultureInfo.InvariantCulture));
else
WriteValue(convertible.ToByte(CultureInfo.InvariantCulture));
return;
case TypeCode.UInt32:
if (nullable)
WriteValue((uint?)convertible.ToUInt32(CultureInfo.InvariantCulture));
else
WriteValue(convertible.ToUInt32(CultureInfo.InvariantCulture));
return;
case TypeCode.Int64:
if (nullable)
WriteValue((long?)convertible.ToInt64(CultureInfo.InvariantCulture));
else
WriteValue(convertible.ToInt64(CultureInfo.InvariantCulture));
return;
case TypeCode.UInt64:
if (nullable)
WriteValue((ulong?)convertible.ToUInt64(CultureInfo.InvariantCulture));
else
WriteValue(convertible.ToUInt64(CultureInfo.InvariantCulture));
return;
case TypeCode.Single:
if (nullable)
WriteValue((float?)convertible.ToSingle(CultureInfo.InvariantCulture));
else
WriteValue(convertible.ToSingle(CultureInfo.InvariantCulture));
return;
case TypeCode.Double:
if (nullable)
WriteValue((double?)convertible.ToDouble(CultureInfo.InvariantCulture));
else
WriteValue(convertible.ToDouble(CultureInfo.InvariantCulture));
return;
case TypeCode.DateTime:
if (nullable)
WriteValue((DateTime?)convertible.ToDateTime(CultureInfo.InvariantCulture));
else
WriteValue(convertible.ToDateTime(CultureInfo.InvariantCulture));
return;
case TypeCode.Decimal:
if (nullable)
WriteValue((decimal?)convertible.ToDecimal(CultureInfo.InvariantCulture));
else
WriteValue(convertible.ToDecimal(CultureInfo.InvariantCulture));
return;
#if !(NETFX_CORE || PORTABLE)
case TypeCode.DBNull:
WriteNull();
return;
#endif
}
}
#if !NET20
else if (value is DateTimeOffset)
{
if (nullable)
WriteValue((DateTimeOffset?)value);
else
WriteValue((DateTimeOffset)value);
return;
}
#endif
else if (value is byte[])
{
WriteValue((byte[])value);
return;
}
else if (value is Guid)
{
if (nullable)
WriteValue((Guid?)value);
else
WriteValue((Guid)value);
return;
}
else if (value is Uri)
{
WriteValue((Uri)value);
return;
}
else if (value is TimeSpan)
{
if (nullable)
WriteValue((TimeSpan?)value);
else
WriteValue((TimeSpan)value);
return;
}
#if !(NET20 || NET35 || SILVERLIGHT || PORTABLE)
else if (value is BigInteger)
{
if (nullable)
WriteValue((BigInteger?)value);
else
WriteValue((BigInteger)value);
return;
}
#endif
throw JsonWriterException.Create(this, "Unsupported type: {0}. Use the JsonSerializer class to get the object's JSON representation.".FormatWith(CultureInfo.InvariantCulture, value.GetType()), null);
else
WriteValue(this, ConvertUtils.GetTypeCode(value), value);
}
#endregion
@@ -1469,5 +1310,156 @@ namespace Newtonsoft.Json
if (_currentState != State.Closed)
Close();
}
internal static void WriteValue(JsonWriter writer, PrimitiveTypeCode typeCode, object value)
{
switch (typeCode)
{
case PrimitiveTypeCode.Char:
writer.WriteValue((char)value);
break;
case PrimitiveTypeCode.CharNullable:
writer.WriteValue((value == null) ? (char?)null : (char)value);
break;
case PrimitiveTypeCode.Boolean:
writer.WriteValue((bool)value);
break;
case PrimitiveTypeCode.BooleanNullable:
writer.WriteValue((value == null) ? (bool?)null : (bool)value);
break;
case PrimitiveTypeCode.SByte:
writer.WriteValue((sbyte)value);
break;
case PrimitiveTypeCode.SByteNullable:
writer.WriteValue((value == null) ? (sbyte?)null : (sbyte)value);
break;
case PrimitiveTypeCode.Int16:
writer.WriteValue((short)value);
break;
case PrimitiveTypeCode.Int16Nullable:
writer.WriteValue((value == null) ? (short?)null : (short)value);
break;
case PrimitiveTypeCode.UInt16:
writer.WriteValue((ushort)value);
break;
case PrimitiveTypeCode.UInt16Nullable:
writer.WriteValue((value == null) ? (ushort?)null : (ushort)value);
break;
case PrimitiveTypeCode.Int32:
writer.WriteValue((int)value);
break;
case PrimitiveTypeCode.Int32Nullable:
writer.WriteValue((value == null) ? (int?)null : (int)value);
break;
case PrimitiveTypeCode.Byte:
writer.WriteValue((byte)value);
break;
case PrimitiveTypeCode.ByteNullable:
writer.WriteValue((value == null) ? (byte?)null : (byte)value);
break;
case PrimitiveTypeCode.UInt32:
writer.WriteValue((uint)value);
break;
case PrimitiveTypeCode.UInt32Nullable:
writer.WriteValue((value == null) ? (uint?)null : (uint)value);
break;
case PrimitiveTypeCode.Int64:
writer.WriteValue((long)value);
break;
case PrimitiveTypeCode.Int64Nullable:
writer.WriteValue((value == null) ? (long?)null : (long)value);
break;
case PrimitiveTypeCode.UInt64:
writer.WriteValue((ulong)value);
break;
case PrimitiveTypeCode.UInt64Nullable:
writer.WriteValue((value == null) ? (ulong?)null : (ulong)value);
break;
case PrimitiveTypeCode.Single:
writer.WriteValue((float)value);
break;
case PrimitiveTypeCode.SingleNullable:
writer.WriteValue((value == null) ? (float?)null : (float)value);
break;
case PrimitiveTypeCode.Double:
writer.WriteValue((double)value);
break;
case PrimitiveTypeCode.DoubleNullable:
writer.WriteValue((value == null) ? (double?)null : (double)value);
break;
case PrimitiveTypeCode.DateTime:
writer.WriteValue((DateTime)value);
break;
case PrimitiveTypeCode.DateTimeNullable:
writer.WriteValue((value == null) ? (DateTime?)null : (DateTime)value);
break;
#if !NET20
case PrimitiveTypeCode.DateTimeOffset:
writer.WriteValue((DateTimeOffset)value);
break;
case PrimitiveTypeCode.DateTimeOffsetNullable:
writer.WriteValue((value == null) ? (DateTimeOffset?)null : (DateTimeOffset)value);
break;
#endif
case PrimitiveTypeCode.Decimal:
writer.WriteValue((decimal)value);
break;
case PrimitiveTypeCode.DecimalNullable:
writer.WriteValue((value == null) ? (decimal?)null : (decimal)value);
break;
case PrimitiveTypeCode.Guid:
writer.WriteValue((Guid)value);
break;
case PrimitiveTypeCode.GuidNullable:
writer.WriteValue((value == null) ? (Guid?)null : (Guid)value);
break;
case PrimitiveTypeCode.TimeSpan:
writer.WriteValue((TimeSpan)value);
break;
case PrimitiveTypeCode.TimeSpanNullable:
writer.WriteValue((value == null) ? (TimeSpan?)null : (TimeSpan)value);
break;
#if !(PORTABLE || NET35 || NET20 || WINDOWS_PHONE || SILVERLIGHT)
case PrimitiveTypeCode.BigInteger:
writer.WriteValue((BigInteger)value);
break;
case PrimitiveTypeCode.BigIntegerNullable:
writer.WriteValue((value == null) ? (BigInteger?)null : (BigInteger)value);
break;
#endif
case PrimitiveTypeCode.Uri:
writer.WriteValue((Uri)value);
break;
case PrimitiveTypeCode.String:
writer.WriteValue((string)value);
break;
case PrimitiveTypeCode.Bytes:
writer.WriteValue((byte[])value);
break;
#if !(PORTABLE || NETFX_CORE)
case PrimitiveTypeCode.DBNull:
writer.WriteNull();
break;
#endif
default:
#if !(PORTABLE || NETFX_CORE)
if (value is IConvertible)
{
// the value is a non-standard IConvertible
// convert to the underlying value and retry
IConvertible convertable = (IConvertible)value;
TypeInformation typeInformation = ConvertUtils.GetTypeInformation(convertable);
object convertedValue = convertable.ToType(typeInformation.Type, CultureInfo.InvariantCulture);
WriteValue(writer, typeInformation.TypeCode, convertedValue);
}
else
#endif
{
throw JsonWriterException.Create(writer, "Unsupported type: {0}. Use the JsonSerializer class to get the object's JSON representation.".FormatWith(CultureInfo.InvariantCulture, value.GetType()), null);
}
break;
}
}
}
}
+61 -96
View File
@@ -1636,126 +1636,91 @@ namespace Newtonsoft.Json.Linq
private object ToObject(Type objectType, bool isNullable)
{
TypeCode typeCode = ConvertUtils.GetTypeCode(objectType);
PrimitiveTypeCode 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;
case PrimitiveTypeCode.BooleanNullable:
return (bool?) this;
case PrimitiveTypeCode.Boolean:
return (bool) this;
case TypeCode.Char:
if (isNullable)
return (char?) this;
case PrimitiveTypeCode.CharNullable:
return (char?) this;
case PrimitiveTypeCode.Char:
return (char) this;
case TypeCode.SByte:
if (isNullable)
return (sbyte?) this;
case PrimitiveTypeCode.SByte:
return (sbyte?) this;
case PrimitiveTypeCode.SByteNullable:
return (sbyte) this;
case TypeCode.Byte:
if (isNullable)
return (byte?) this;
case PrimitiveTypeCode.ByteNullable:
return (byte?) this;
case PrimitiveTypeCode.Byte:
return (byte) this;
case TypeCode.Int16:
if (isNullable)
return (short?) this;
case PrimitiveTypeCode.Int16Nullable:
return (short?) this;
case PrimitiveTypeCode.Int16:
return (short) this;
case TypeCode.UInt16:
if (isNullable)
return (ushort?) this;
case PrimitiveTypeCode.UInt16Nullable:
return (ushort?) this;
case PrimitiveTypeCode.UInt16:
return (ushort) this;
case TypeCode.Int32:
if (isNullable)
return (int?) this;
case PrimitiveTypeCode.Int32Nullable:
return (int?) this;
case PrimitiveTypeCode.Int32:
return (int) this;
case TypeCode.UInt32:
if (isNullable)
return (uint?) this;
case PrimitiveTypeCode.UInt32Nullable:
return (uint?) this;
case PrimitiveTypeCode.UInt32:
return (uint) this;
case TypeCode.Int64:
if (isNullable)
return (long?) this;
case PrimitiveTypeCode.Int64Nullable:
return (long?) this;
case PrimitiveTypeCode.Int64:
return (long) this;
case TypeCode.UInt64:
if (isNullable)
return (ulong?) this;
case PrimitiveTypeCode.UInt64Nullable:
return (ulong?) this;
case PrimitiveTypeCode.UInt64:
return (ulong) this;
case TypeCode.Single:
if (isNullable)
return (float?) this;
case PrimitiveTypeCode.SingleNullable:
return (float?) this;
case PrimitiveTypeCode.Single:
return (float) this;
case TypeCode.Double:
if (isNullable)
return (double?) this;
case PrimitiveTypeCode.DoubleNullable:
return (double?) this;
case PrimitiveTypeCode.Double:
return (double) this;
case TypeCode.Decimal:
if (isNullable)
return (decimal?) this;
case PrimitiveTypeCode.DecimalNullable:
return (decimal?) this;
case PrimitiveTypeCode.Decimal:
return (decimal) this;
case TypeCode.DateTime:
if (isNullable)
return (DateTime?) this;
case PrimitiveTypeCode.DateTimeNullable:
return (DateTime?) this;
case PrimitiveTypeCode.DateTime:
return (DateTime) this;
case TypeCode.String:
return (string) this;
}
#if !NET20
if (objectType == typeof (DateTimeOffset))
{
if (isNullable)
case PrimitiveTypeCode.DateTimeOffsetNullable:
return (DateTimeOffset?) this;
return (DateTimeOffset) this;
}
case PrimitiveTypeCode.DateTimeOffset:
return (DateTimeOffset) this;
#endif
if (objectType == typeof (Guid))
{
if (isNullable)
case PrimitiveTypeCode.String:
return (string) this;
case PrimitiveTypeCode.GuidNullable:
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;
}
case PrimitiveTypeCode.Guid:
return (Guid) this;
case PrimitiveTypeCode.Uri:
return (Uri) this;
case PrimitiveTypeCode.TimeSpanNullable:
return (TimeSpan?)this;
case PrimitiveTypeCode.TimeSpan:
return (TimeSpan)this;
#if !(NET20 || NET35 || SILVERLIGHT || PORTABLE)
if (objectType == typeof(BigInteger))
{
if (isNullable)
case PrimitiveTypeCode.BigIntegerNullable:
return (BigInteger?)this;
return (BigInteger)this;
}
case PrimitiveTypeCode.BigInteger:
return (BigInteger)this;
#endif
}
return ToObject(objectType, new JsonSerializer());
}
@@ -30,9 +30,6 @@ using System.Collections.Generic;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Utilities;
using Newtonsoft.Json.Serialization;
#if NETFX_CORE
using IConvertible = Newtonsoft.Json.Utilities.Convertible;
#endif
#if NET20
using Newtonsoft.Json.Utilities.LinqBridge;
#else
@@ -321,8 +318,10 @@ namespace Newtonsoft.Json.Schema
if (keyType != null)
{
JsonContract keyContract = ContractResolver.ResolveContract(keyType);
// can be converted to a string
if (ConvertUtils.IsConvertible(keyType))
if (keyContract.ContractType == JsonContractType.Primitive)
{
CurrentSchema.AdditionalProperties = GenerateInternal(valueType, Required.Default, false);
}
@@ -421,38 +420,44 @@ namespace Newtonsoft.Json.Schema
type = Nullable.GetUnderlyingType(type);
}
TypeCode typeCode = ConvertUtils.GetTypeCode(type);
PrimitiveTypeCode typeCode = ConvertUtils.GetTypeCode(type);
switch (typeCode)
{
case TypeCode.Empty:
case TypeCode.Object:
case PrimitiveTypeCode.Empty:
case PrimitiveTypeCode.Object:
return schemaType | JsonSchemaType.String;
#if !(NETFX_CORE || PORTABLE)
case TypeCode.DBNull:
case PrimitiveTypeCode.DBNull:
return schemaType | JsonSchemaType.Null;
#endif
case TypeCode.Boolean:
case PrimitiveTypeCode.Boolean:
return schemaType | JsonSchemaType.Boolean;
case TypeCode.Char:
case PrimitiveTypeCode.Char:
return schemaType | JsonSchemaType.String;
case TypeCode.SByte:
case TypeCode.Byte:
case TypeCode.Int16:
case TypeCode.UInt16:
case TypeCode.Int32:
case TypeCode.UInt32:
case TypeCode.Int64:
case TypeCode.UInt64:
case PrimitiveTypeCode.SByte:
case PrimitiveTypeCode.Byte:
case PrimitiveTypeCode.Int16:
case PrimitiveTypeCode.UInt16:
case PrimitiveTypeCode.Int32:
case PrimitiveTypeCode.UInt32:
case PrimitiveTypeCode.Int64:
case PrimitiveTypeCode.UInt64:
case PrimitiveTypeCode.BigInteger:
return schemaType | JsonSchemaType.Integer;
case TypeCode.Single:
case TypeCode.Double:
case TypeCode.Decimal:
case PrimitiveTypeCode.Single:
case PrimitiveTypeCode.Double:
case PrimitiveTypeCode.Decimal:
return schemaType | JsonSchemaType.Float;
// convert to string?
case TypeCode.DateTime:
case PrimitiveTypeCode.DateTime:
case PrimitiveTypeCode.DateTimeOffset:
return schemaType | JsonSchemaType.String;
case TypeCode.String:
case PrimitiveTypeCode.String:
case PrimitiveTypeCode.Uri:
case PrimitiveTypeCode.Guid:
case PrimitiveTypeCode.TimeSpan:
case PrimitiveTypeCode.Bytes:
return schemaType | JsonSchemaType.String;
default:
throw new JsonException("Unexpected type code '{0}' for type '{1}'.".FormatWith(CultureInfo.InvariantCulture, typeCode, type));
@@ -781,7 +781,7 @@ namespace Newtonsoft.Json.Serialization
{
Type t = ReflectionUtils.EnsureNotNullableType(objectType);
if (JsonConvert.IsJsonPrimitiveType(t))
if (JsonConvert.IsJsonPrimitiveType(objectType))
return CreatePrimitiveContract(objectType);
if (JsonTypeReflector.GetJsonObjectAttribute(t) != null)
@@ -28,9 +28,6 @@ using System.Collections.Generic;
using System.Reflection;
using System.Runtime.Serialization;
using Newtonsoft.Json.Utilities;
#if NETFX_CORE
using IConvertible = Newtonsoft.Json.Utilities.Convertible;
#endif
namespace Newtonsoft.Json.Serialization
{
@@ -24,8 +24,8 @@
#endregion
using System;
using System.Collections.Generic;
#if !(PORTABLE || NET35 || NET20 || WINDOWS_PHONE || SILVERLIGHT)
using System.Globalization;
using System.Numerics;
#endif
using Newtonsoft.Json.Utilities;
@@ -37,57 +37,6 @@ namespace Newtonsoft.Json.Serialization
/// </summary>
public class JsonPrimitiveContract : JsonContract
{
private static readonly Dictionary<Type, PrimitiveTypeCode> TypeCodeMap =
new Dictionary<Type, PrimitiveTypeCode>
{
{ typeof(char), PrimitiveTypeCode.Char },
{ typeof(char?), PrimitiveTypeCode.CharNullable },
{ typeof(bool), PrimitiveTypeCode.Boolean },
{ typeof(bool?), PrimitiveTypeCode.BooleanNullable },
{ typeof(sbyte), PrimitiveTypeCode.SByte },
{ typeof(sbyte?), PrimitiveTypeCode.SByteNullable },
{ typeof(short), PrimitiveTypeCode.Int16 },
{ typeof(short?), PrimitiveTypeCode.Int16Nullable },
{ typeof(ushort), PrimitiveTypeCode.UInt16 },
{ typeof(ushort?), PrimitiveTypeCode.UInt16Nullable },
{ typeof(int), PrimitiveTypeCode.Int32 },
{ typeof(int?), PrimitiveTypeCode.Int32Nullable },
{ typeof(byte), PrimitiveTypeCode.Byte },
{ typeof(byte?), PrimitiveTypeCode.ByteNullable },
{ typeof(uint), PrimitiveTypeCode.UInt32 },
{ typeof(uint?), PrimitiveTypeCode.UInt32Nullable },
{ typeof(long), PrimitiveTypeCode.Int64 },
{ typeof(long?), PrimitiveTypeCode.Int64Nullable },
{ typeof(ulong), PrimitiveTypeCode.UInt64 },
{ typeof(ulong?), PrimitiveTypeCode.UInt64Nullable },
{ typeof(float), PrimitiveTypeCode.Single },
{ typeof(float?), PrimitiveTypeCode.SingleNullable },
{ typeof(double), PrimitiveTypeCode.Double },
{ typeof(double?), PrimitiveTypeCode.DoubleNullable },
{ typeof(DateTime), PrimitiveTypeCode.DateTime },
{ typeof(DateTime?), PrimitiveTypeCode.DateTimeNullable },
#if !NET20
{ typeof(DateTimeOffset), PrimitiveTypeCode.DateTimeOffset },
{ typeof(DateTimeOffset?), PrimitiveTypeCode.DateTimeOffsetNullable },
#endif
{ typeof(decimal), PrimitiveTypeCode.Decimal },
{ typeof(decimal?), PrimitiveTypeCode.DecimalNullable },
{ typeof(Guid), PrimitiveTypeCode.Guid },
{ typeof(Guid?), PrimitiveTypeCode.GuidNullable },
{ typeof(TimeSpan), PrimitiveTypeCode.TimeSpan },
{ typeof(TimeSpan?), PrimitiveTypeCode.TimeSpanNullable },
#if !(PORTABLE || NET35 || NET20 || WINDOWS_PHONE || SILVERLIGHT)
{ typeof(BigInteger), PrimitiveTypeCode.BigInteger },
{ typeof(BigInteger?), PrimitiveTypeCode.BigIntegerNullable },
#endif
{ typeof(Uri), PrimitiveTypeCode.Uri },
{ typeof(string), PrimitiveTypeCode.String },
{ typeof(byte[]), PrimitiveTypeCode.Bytes },
#if !(PORTABLE || NETFX_CORE)
{ typeof(DBNull), PrimitiveTypeCode.DBNull }
#endif
};
internal PrimitiveTypeCode TypeCode { get; set; }
/// <summary>
@@ -99,256 +48,7 @@ namespace Newtonsoft.Json.Serialization
{
ContractType = JsonContractType.Primitive;
// get the underlying enum value
Type t;
if (ReflectionUtils.IsNullableType(underlyingType))
t = Nullable.GetUnderlyingType(underlyingType).IsEnum() ? ReflectionUtils.MakeGenericType(typeof(Nullable<>), Enum.GetUnderlyingType(Nullable.GetUnderlyingType(underlyingType))) : underlyingType;
else
t = underlyingType.IsEnum() ? Enum.GetUnderlyingType(underlyingType) : underlyingType;
PrimitiveTypeCode typeCode;
TypeCodeMap.TryGetValue(t, out typeCode);
TypeCode = typeCode;
TypeCode = ConvertUtils.GetTypeCode(underlyingType);
}
internal void WriteValue(JsonWriter writer, object value)
{
switch (TypeCode)
{
case PrimitiveTypeCode.Char:
writer.WriteValue((char)value);
break;
case PrimitiveTypeCode.CharNullable:
if (value != null)
writer.WriteValue((char)value);
else
writer.WriteNull();
break;
case PrimitiveTypeCode.Boolean:
writer.WriteValue((bool)value);
break;
case PrimitiveTypeCode.BooleanNullable:
if (value != null)
writer.WriteValue((bool)value);
else
writer.WriteNull();
break;
case PrimitiveTypeCode.SByte:
writer.WriteValue((sbyte)value);
break;
case PrimitiveTypeCode.SByteNullable:
if (value != null)
writer.WriteValue((sbyte)value);
else
writer.WriteNull();
break;
case PrimitiveTypeCode.Int16:
writer.WriteValue((short)value);
break;
case PrimitiveTypeCode.Int16Nullable:
if (value != null)
writer.WriteValue((short)value);
else
writer.WriteNull();
break;
case PrimitiveTypeCode.UInt16:
writer.WriteValue((ushort)value);
break;
case PrimitiveTypeCode.UInt16Nullable:
if (value != null)
writer.WriteValue((ushort)value);
else
writer.WriteNull();
break;
case PrimitiveTypeCode.Int32:
writer.WriteValue((int)value);
break;
case PrimitiveTypeCode.Int32Nullable:
if (value != null)
writer.WriteValue((int)value);
else
writer.WriteNull();
break;
case PrimitiveTypeCode.Byte:
writer.WriteValue((byte)value);
break;
case PrimitiveTypeCode.ByteNullable:
if (value != null)
writer.WriteValue((byte)value);
else
writer.WriteNull();
break;
case PrimitiveTypeCode.UInt32:
writer.WriteValue((uint)value);
break;
case PrimitiveTypeCode.UInt32Nullable:
if (value != null)
writer.WriteValue((uint)value);
else
writer.WriteNull();
break;
case PrimitiveTypeCode.Int64:
writer.WriteValue((long)value);
break;
case PrimitiveTypeCode.Int64Nullable:
if (value != null)
writer.WriteValue((long)value);
else
writer.WriteNull();
break;
case PrimitiveTypeCode.UInt64:
writer.WriteValue((ulong)value);
break;
case PrimitiveTypeCode.UInt64Nullable:
if (value != null)
writer.WriteValue((ulong)value);
else
writer.WriteNull();
break;
case PrimitiveTypeCode.Single:
writer.WriteValue((float)value);
break;
case PrimitiveTypeCode.SingleNullable:
// use nullable WriteValue to handle NaN, Infinity with FloatFormatHandling
if (value != null)
writer.WriteValue((float?)value);
else
writer.WriteNull();
break;
case PrimitiveTypeCode.Double:
writer.WriteValue((double)value);
break;
case PrimitiveTypeCode.DoubleNullable:
// use nullable WriteValue to handle NaN, Infinity with FloatFormatHandling
if (value != null)
writer.WriteValue((double?)value);
else
writer.WriteNull();
break;
case PrimitiveTypeCode.DateTime:
writer.WriteValue((DateTime)value);
break;
case PrimitiveTypeCode.DateTimeNullable:
if (value != null)
writer.WriteValue((DateTime)value);
else
writer.WriteNull();
break;
#if !NET20
case PrimitiveTypeCode.DateTimeOffset:
writer.WriteValue((DateTimeOffset)value);
break;
case PrimitiveTypeCode.DateTimeOffsetNullable:
if (value != null)
writer.WriteValue((DateTimeOffset)value);
else
writer.WriteNull();
break;
#endif
case PrimitiveTypeCode.Decimal:
writer.WriteValue((decimal)value);
break;
case PrimitiveTypeCode.DecimalNullable:
if (value != null)
writer.WriteValue((decimal)value);
else
writer.WriteNull();
break;
case PrimitiveTypeCode.Guid:
writer.WriteValue((Guid)value);
break;
case PrimitiveTypeCode.GuidNullable:
if (value != null)
writer.WriteValue((Guid)value);
else
writer.WriteNull();
break;
case PrimitiveTypeCode.TimeSpan:
writer.WriteValue((TimeSpan)value);
break;
case PrimitiveTypeCode.TimeSpanNullable:
if (value != null)
writer.WriteValue((TimeSpan)value);
else
writer.WriteNull();
break;
#if !(PORTABLE || NET35 || NET20 || WINDOWS_PHONE || SILVERLIGHT)
case PrimitiveTypeCode.BigInteger:
writer.WriteValue((BigInteger)value);
break;
case PrimitiveTypeCode.BigIntegerNullable:
if (value != null)
writer.WriteValue((BigInteger)value);
else
writer.WriteNull();
break;
#endif
case PrimitiveTypeCode.Uri:
writer.WriteValue((Uri)value);
break;
case PrimitiveTypeCode.String:
writer.WriteValue((string)value);
break;
case PrimitiveTypeCode.Bytes:
writer.WriteValue((byte[])value);
break;
#if !(PORTABLE || NETFX_CORE)
case PrimitiveTypeCode.DBNull:
writer.WriteNull();
break;
#endif
default:
throw new ArgumentOutOfRangeException("Could not write type: " + UnderlyingType);
}
}
}
internal enum PrimitiveTypeCode
{
Unknown,
Char,
CharNullable,
Boolean,
BooleanNullable,
SByte,
SByteNullable,
Int16,
Int16Nullable,
UInt16,
UInt16Nullable,
Int32,
Int32Nullable,
Byte,
ByteNullable,
UInt32,
UInt32Nullable,
Int64,
Int64Nullable,
UInt64,
UInt64Nullable,
Single,
SingleNullable,
Double,
DoubleNullable,
DateTime,
DateTimeNullable,
#if !NET20
DateTimeOffset,
DateTimeOffsetNullable,
#endif
Decimal,
DecimalNullable,
Guid,
GuidNullable,
TimeSpan,
TimeSpanNullable,
#if !(PORTABLE || NET35 || NET20 || WINDOWS_PHONE || SILVERLIGHT)
BigInteger,
BigIntegerNullable,
#endif
Uri,
String,
Bytes,
DBNull
}
}
@@ -693,11 +693,13 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
if (contract.IsConvertable)
{
JsonPrimitiveContract primitiveContract = (JsonPrimitiveContract)contract;
if (contract.NonNullableUnderlyingType.IsEnum())
{
if (value is string)
return Enum.Parse(contract.NonNullableUnderlyingType, value.ToString(), true);
else if (ConvertUtils.IsInteger(value))
else if (ConvertUtils.IsInteger(primitiveContract.TypeCode))
return Enum.ToObject(contract.NonNullableUnderlyingType, value);
}
@@ -706,6 +708,7 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
return ConvertUtils.FromBigInteger((BigInteger)value, targetType);
#endif
// this won't work when converting to a custom IConvertible
return Convert.ChangeType(value, contract.NonNullableUnderlyingType, culture);
}
@@ -966,6 +969,7 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
contract.ItemContract = GetContractSafe(contract.DictionaryValueType);
JsonConverter dictionaryValueConverter = contract.ItemConverter ?? GetConverter(contract.ItemContract, null, contract, containerProperty);
PrimitiveTypeCode keyTypeCode = (contract.KeyContract is JsonPrimitiveContract) ? ((JsonPrimitiveContract)contract.KeyContract).TypeCode : PrimitiveTypeCode.Empty;
bool finished = false;
do
@@ -979,11 +983,13 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
try
{
// this is for correctly reading ISO and MS formatted dictionary keys
if (contract.DictionaryKeyType == typeof(DateTime) && JsonConvert.TryParseDateTime(keyValue.ToString(), DateParseHandling.DateTime, reader.DateTimeZoneHandling, out keyValue))
if ((keyTypeCode == PrimitiveTypeCode.DateTime || keyTypeCode == PrimitiveTypeCode.DateTimeNullable)
&& JsonConvert.TryParseDateTime(keyValue.ToString(), DateParseHandling.DateTime, reader.DateTimeZoneHandling, out keyValue))
{
}
#if !NET20
else if (contract.DictionaryKeyType == typeof(DateTimeOffset) && JsonConvert.TryParseDateTime(keyValue.ToString(), DateParseHandling.DateTimeOffset, reader.DateTimeZoneHandling, out keyValue))
else if ((keyTypeCode == PrimitiveTypeCode.DateTimeOffset || keyTypeCode == PrimitiveTypeCode.DateTimeOffsetNullable)
&& JsonConvert.TryParseDateTime(keyValue.ToString(), DateParseHandling.DateTimeOffset, reader.DateTimeZoneHandling, out keyValue))
{
}
#endif
@@ -94,14 +94,14 @@ namespace Newtonsoft.Json.Serialization
WriteTypeProperty(writer, contract.CreatedType);
writer.WritePropertyName(JsonTypeReflector.ValuePropertyName);
contract.WriteValue(writer, value);
JsonWriter.WriteValue(writer, contract.TypeCode, value);
writer.WriteEndObject();
return;
}
}
contract.WriteValue(writer, value);
JsonWriter.WriteValue(writer, contract.TypeCode, value);
}
private void SerializeValue(JsonWriter writer, object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
@@ -827,12 +827,15 @@ To fix this error either change the environment to be fully trusted, change the
if (contract.ItemContract == null)
contract.ItemContract = Serializer.ContractResolver.ResolveContract(contract.DictionaryValueType ?? typeof(object));
if (contract.KeyContract == null)
contract.KeyContract = Serializer.ContractResolver.ResolveContract(contract.DictionaryKeyType ?? typeof(object));
int initialDepth = writer.Top;
foreach (DictionaryEntry entry in values)
{
bool escape;
string propertyName = GetPropertyName(writer, entry, out escape);
string propertyName = GetPropertyName(writer, entry, contract.KeyContract, out escape);
propertyName = (contract.PropertyNameResolver != null)
? contract.PropertyNameResolver(propertyName)
@@ -874,32 +877,36 @@ To fix this error either change the environment to be fully trusted, change the
OnSerialized(writer, contract, underlyingDictionary);
}
private string GetPropertyName(JsonWriter writer, DictionaryEntry entry, out bool escape)
private string GetPropertyName(JsonWriter writer, DictionaryEntry entry, JsonContract contract, out bool escape)
{
object key = entry.Key;
string propertyName;
if (key is DateTime)
JsonPrimitiveContract primitiveContract = contract as JsonPrimitiveContract;
if (primitiveContract != null)
{
escape = false;
StringWriter sw = new StringWriter(CultureInfo.InvariantCulture);
JsonConvert.WriteDateTimeString(sw, (DateTime)key, writer.DateFormatHandling, writer.DateFormatString, writer.Culture);
return sw.ToString();
}
if (primitiveContract.TypeCode == PrimitiveTypeCode.DateTime || primitiveContract.TypeCode == PrimitiveTypeCode.DateTimeNullable)
{
escape = false;
StringWriter sw = new StringWriter(CultureInfo.InvariantCulture);
JsonConvert.WriteDateTimeString(sw, (DateTime)key, writer.DateFormatHandling, writer.DateFormatString, writer.Culture);
return sw.ToString();
}
#if !NET20
else if (key is DateTimeOffset)
{
escape = false;
StringWriter sw = new StringWriter(CultureInfo.InvariantCulture);
JsonConvert.WriteDateTimeOffsetString(sw, (DateTimeOffset)key, writer.DateFormatHandling, writer.DateFormatString, writer.Culture);
return sw.ToString();
}
else if (primitiveContract.TypeCode == PrimitiveTypeCode.DateTimeOffset || primitiveContract.TypeCode == PrimitiveTypeCode.DateTimeOffsetNullable)
{
escape = false;
StringWriter sw = new StringWriter(CultureInfo.InvariantCulture);
JsonConvert.WriteDateTimeOffsetString(sw, (DateTimeOffset)key, writer.DateFormatHandling, writer.DateFormatString, writer.Culture);
return sw.ToString();
}
#endif
else if (ConvertUtils.IsConvertible(key))
{
escape = true;
return Convert.ToString(key, CultureInfo.InvariantCulture);
else
{
escape = true;
return Convert.ToString(key, CultureInfo.InvariantCulture);
}
}
else if (TryConvertToString(key, key.GetType(), out propertyName))
{
+166 -165
View File
@@ -24,6 +24,7 @@
#endregion
using System;
using System.Collections.Generic;
using System.Globalization;
using System.ComponentModel;
#if !(NET20 || NET35 || SILVERLIGHT || PORTABLE)
@@ -38,181 +39,176 @@ using Newtonsoft.Json.Utilities.LinqBridge;
#if !(SILVERLIGHT || NETFX_CORE || PORTABLE)
using System.Data.SqlTypes;
#endif
#if NETFX_CORE || PORTABLE
using IConvertible = Newtonsoft.Json.Utilities.Convertible;
#endif
namespace Newtonsoft.Json.Utilities
{
#if NETFX_CORE || PORTABLE
internal class Convertible
internal enum PrimitiveTypeCode
{
private object _underlyingValue;
public Convertible(object o)
{
_underlyingValue = o;
}
public TypeCode GetTypeCode()
{
return ConvertUtils.GetTypeCode(_underlyingValue);
}
public bool ToBoolean(IFormatProvider provider)
{
return Convert.ToBoolean(_underlyingValue, provider);
}
public byte ToByte(IFormatProvider provider)
{
return Convert.ToByte(_underlyingValue, provider);
}
public char ToChar(IFormatProvider provider)
{
return Convert.ToChar(_underlyingValue, provider);
}
public DateTime ToDateTime(IFormatProvider provider)
{
return Convert.ToDateTime(_underlyingValue, provider);
}
public decimal ToDecimal(IFormatProvider provider)
{
return Convert.ToDecimal(_underlyingValue, provider);
}
public double ToDouble(IFormatProvider provider)
{
return Convert.ToDouble(_underlyingValue, provider);
}
public short ToInt16(IFormatProvider provider)
{
return Convert.ToInt16(_underlyingValue, provider);
}
public int ToInt32(IFormatProvider provider)
{
return Convert.ToInt32(_underlyingValue, provider);
}
public long ToInt64(IFormatProvider provider)
{
return Convert.ToInt64(_underlyingValue, provider);
}
public sbyte ToSByte(IFormatProvider provider)
{
return Convert.ToSByte(_underlyingValue, provider);
}
public float ToSingle(IFormatProvider provider)
{
return Convert.ToSingle(_underlyingValue, provider);
}
public string ToString(IFormatProvider provider)
{
return Convert.ToString(_underlyingValue, provider);
}
public object ToType(Type conversionType, IFormatProvider provider)
{
return Convert.ChangeType(_underlyingValue, conversionType, provider);
}
public ushort ToUInt16(IFormatProvider provider)
{
return Convert.ToUInt16(_underlyingValue, provider);
}
public uint ToUInt32(IFormatProvider provider)
{
return Convert.ToUInt32(_underlyingValue, provider);
}
public ulong ToUInt64(IFormatProvider provider)
{
return Convert.ToUInt64(_underlyingValue, provider);
}
}
Empty,
Object,
Char,
CharNullable,
Boolean,
BooleanNullable,
SByte,
SByteNullable,
Int16,
Int16Nullable,
UInt16,
UInt16Nullable,
Int32,
Int32Nullable,
Byte,
ByteNullable,
UInt32,
UInt32Nullable,
Int64,
Int64Nullable,
UInt64,
UInt64Nullable,
Single,
SingleNullable,
Double,
DoubleNullable,
DateTime,
DateTimeNullable,
#if !NET20
DateTimeOffset,
DateTimeOffsetNullable,
#endif
Decimal,
DecimalNullable,
Guid,
GuidNullable,
TimeSpan,
TimeSpanNullable,
#if !(PORTABLE || NET35 || NET20 || WINDOWS_PHONE || SILVERLIGHT)
BigInteger,
BigIntegerNullable,
#endif
Uri,
String,
Bytes,
DBNull
}
internal class TypeInformation
{
public Type Type { get; set; }
public PrimitiveTypeCode TypeCode { get; set; }
}
internal static class ConvertUtils
{
public static TypeCode GetTypeCode(this IConvertible convertible)
{
#if !(NETFX_CORE || PORTABLE)
return convertible.GetTypeCode();
#else
return GetTypeCode((object)convertible);
private static readonly Dictionary<Type, PrimitiveTypeCode> TypeCodeMap =
new Dictionary<Type, PrimitiveTypeCode>
{
{ typeof(char), PrimitiveTypeCode.Char },
{ typeof(char?), PrimitiveTypeCode.CharNullable },
{ typeof(bool), PrimitiveTypeCode.Boolean },
{ typeof(bool?), PrimitiveTypeCode.BooleanNullable },
{ typeof(sbyte), PrimitiveTypeCode.SByte },
{ typeof(sbyte?), PrimitiveTypeCode.SByteNullable },
{ typeof(short), PrimitiveTypeCode.Int16 },
{ typeof(short?), PrimitiveTypeCode.Int16Nullable },
{ typeof(ushort), PrimitiveTypeCode.UInt16 },
{ typeof(ushort?), PrimitiveTypeCode.UInt16Nullable },
{ typeof(int), PrimitiveTypeCode.Int32 },
{ typeof(int?), PrimitiveTypeCode.Int32Nullable },
{ typeof(byte), PrimitiveTypeCode.Byte },
{ typeof(byte?), PrimitiveTypeCode.ByteNullable },
{ typeof(uint), PrimitiveTypeCode.UInt32 },
{ typeof(uint?), PrimitiveTypeCode.UInt32Nullable },
{ typeof(long), PrimitiveTypeCode.Int64 },
{ typeof(long?), PrimitiveTypeCode.Int64Nullable },
{ typeof(ulong), PrimitiveTypeCode.UInt64 },
{ typeof(ulong?), PrimitiveTypeCode.UInt64Nullable },
{ typeof(float), PrimitiveTypeCode.Single },
{ typeof(float?), PrimitiveTypeCode.SingleNullable },
{ typeof(double), PrimitiveTypeCode.Double },
{ typeof(double?), PrimitiveTypeCode.DoubleNullable },
{ typeof(DateTime), PrimitiveTypeCode.DateTime },
{ typeof(DateTime?), PrimitiveTypeCode.DateTimeNullable },
#if !NET20
{ typeof(DateTimeOffset), PrimitiveTypeCode.DateTimeOffset },
{ typeof(DateTimeOffset?), PrimitiveTypeCode.DateTimeOffsetNullable },
#endif
}
public static TypeCode GetTypeCode(object o)
{
#if !(NETFX_CORE || PORTABLE)
return System.Convert.GetTypeCode(o);
#else
return GetTypeCode(o.GetType());
{ typeof(decimal), PrimitiveTypeCode.Decimal },
{ typeof(decimal?), PrimitiveTypeCode.DecimalNullable },
{ typeof(Guid), PrimitiveTypeCode.Guid },
{ typeof(Guid?), PrimitiveTypeCode.GuidNullable },
{ typeof(TimeSpan), PrimitiveTypeCode.TimeSpan },
{ typeof(TimeSpan?), PrimitiveTypeCode.TimeSpanNullable },
#if !(PORTABLE || NET35 || NET20 || WINDOWS_PHONE || SILVERLIGHT)
{ typeof(BigInteger), PrimitiveTypeCode.BigInteger },
{ typeof(BigInteger?), PrimitiveTypeCode.BigIntegerNullable },
#endif
}
{ typeof(Uri), PrimitiveTypeCode.Uri },
{ typeof(string), PrimitiveTypeCode.String },
{ typeof(byte[]), PrimitiveTypeCode.Bytes },
#if !(PORTABLE || NETFX_CORE)
{ typeof(DBNull), PrimitiveTypeCode.DBNull }
#endif
};
public static TypeCode GetTypeCode(Type t)
private static readonly List<TypeInformation> PrimitiveTypeCodes = new List<TypeInformation>
{
new TypeInformation { Type = typeof(object), TypeCode = PrimitiveTypeCode.Empty },
new TypeInformation { Type = typeof(object), TypeCode = PrimitiveTypeCode.Object },
new TypeInformation { Type = typeof(object), TypeCode = PrimitiveTypeCode.DBNull },
new TypeInformation { Type = typeof(bool), TypeCode = PrimitiveTypeCode.Boolean },
new TypeInformation { Type = typeof(char), TypeCode = PrimitiveTypeCode.Char },
new TypeInformation { Type = typeof(sbyte), TypeCode = PrimitiveTypeCode.SByte },
new TypeInformation { Type = typeof(byte), TypeCode = PrimitiveTypeCode.Byte },
new TypeInformation { Type = typeof(short), TypeCode = PrimitiveTypeCode.Int16 },
new TypeInformation { Type = typeof(ushort), TypeCode = PrimitiveTypeCode.UInt16 },
new TypeInformation { Type = typeof(int), TypeCode = PrimitiveTypeCode.Int32 },
new TypeInformation { Type = typeof(uint), TypeCode = PrimitiveTypeCode.UInt32 },
new TypeInformation { Type = typeof(long), TypeCode = PrimitiveTypeCode.Int64 },
new TypeInformation { Type = typeof(ulong), TypeCode = PrimitiveTypeCode.UInt64 },
new TypeInformation { Type = typeof(float), TypeCode = PrimitiveTypeCode.Single },
new TypeInformation { Type = typeof(double), TypeCode = PrimitiveTypeCode.Double },
new TypeInformation { Type = typeof(decimal), TypeCode = PrimitiveTypeCode.Decimal },
new TypeInformation { Type = typeof(DateTime), TypeCode = PrimitiveTypeCode.DateTime },
new TypeInformation { Type = typeof(object), TypeCode = PrimitiveTypeCode.Empty }, // no 17 in TypeCode for some reason
new TypeInformation { Type = typeof(string), TypeCode = PrimitiveTypeCode.String }
};
public static PrimitiveTypeCode GetTypeCode(Type t)
{
#if !(NETFX_CORE || PORTABLE)
return Type.GetTypeCode(t);
#else
if (t == typeof(bool))
return TypeCode.Boolean;
if (t == typeof(byte))
return TypeCode.Byte;
if (t == typeof(char))
return TypeCode.Char;
if (t == typeof(DateTime))
return TypeCode.DateTime;
if (t == typeof(decimal))
return TypeCode.Decimal;
if (t == typeof(double))
return TypeCode.Double;
if (t == typeof(short))
return TypeCode.Int16;
if (t == typeof(int))
return TypeCode.Int32;
if (t == typeof(long))
return TypeCode.Int64;
if (t == typeof(sbyte))
return TypeCode.SByte;
if (t == typeof(float))
return TypeCode.Single;
if (t == typeof(string))
return TypeCode.String;
if (t == typeof(ushort))
return TypeCode.UInt16;
if (t == typeof(uint))
return TypeCode.UInt32;
if (t == typeof(ulong))
return TypeCode.UInt64;
PrimitiveTypeCode typeCode;
if (TypeCodeMap.TryGetValue(t, out typeCode))
return typeCode;
if (t.IsEnum())
return GetTypeCode(Enum.GetUnderlyingType(t));
return TypeCode.Object;
#endif
// performance?
if (ReflectionUtils.IsNullableType(t))
{
Type nonNullable = Nullable.GetUnderlyingType(t);
if (nonNullable.IsEnum())
{
Type nullableUnderlyingType = ReflectionUtils.MakeGenericType(typeof (Nullable<>), Enum.GetUnderlyingType(nonNullable));
return GetTypeCode(nullableUnderlyingType);
}
}
return PrimitiveTypeCode.Object;
}
public static IConvertible ToConvertible(object o)
public static PrimitiveTypeCode GetTypeCode(object o)
{
#if !(NETFX_CORE || PORTABLE)
return o as IConvertible;
#else
if (!IsConvertible(o))
return null;
return new IConvertible(o);
#endif
return GetTypeCode(o.GetType());
}
public static bool IsConvertible(object o)
#if !(NETFX_CORE || PORTABLE)
public static TypeInformation GetTypeInformation(IConvertible convertable)
{
#if !(NETFX_CORE || PORTABLE)
return o is IConvertible;
#else
if (o == null)
return false;
return (
o is bool || o is byte || o is char || o is DateTime || o is decimal || o is double || o is short || o is int ||
o is long || o is sbyte || o is float || o is string || o is ushort || o is uint || o is ulong || o is Enum);
#endif
TypeInformation typeInformation = PrimitiveTypeCodes[(int) convertable.GetTypeCode()];
return typeInformation;
}
#endif
public static bool IsConvertible(Type t)
{
@@ -328,10 +324,15 @@ namespace Newtonsoft.Json.Utilities
return (float) i;
if (targetType == typeof (ulong))
return (ulong) i;
if (IsConvertible(targetType))
return System.Convert.ChangeType((long) i, targetType, CultureInfo.InvariantCulture);
throw new InvalidOperationException("Can not convert from BigInteger to {0}.".FormatWith(CultureInfo.InvariantCulture, targetType));
try
{
return System.Convert.ChangeType((long)i, targetType, CultureInfo.InvariantCulture);
}
catch (Exception ex)
{
throw new InvalidOperationException("Can not convert from BigInteger to {0}.".FormatWith(CultureInfo.InvariantCulture, targetType), ex);
}
}
#endif
@@ -357,7 +358,7 @@ namespace Newtonsoft.Json.Utilities
return initialValue;
// use Convert.ChangeType if both types are IConvertible
if (ConvertUtils.IsConvertible(initialValue) && ConvertUtils.IsConvertible(targetType))
if (ConvertUtils.IsConvertible(initialValue.GetType()) && ConvertUtils.IsConvertible(targetType))
{
if (targetType.IsEnum())
{
@@ -550,14 +551,14 @@ namespace Newtonsoft.Json.Utilities
{
switch (GetTypeCode(value))
{
case TypeCode.SByte:
case TypeCode.Byte:
case TypeCode.Int16:
case TypeCode.UInt16:
case TypeCode.Int32:
case TypeCode.UInt32:
case TypeCode.Int64:
case TypeCode.UInt64:
case PrimitiveTypeCode.SByte:
case PrimitiveTypeCode.Byte:
case PrimitiveTypeCode.Int16:
case PrimitiveTypeCode.UInt16:
case PrimitiveTypeCode.Int32:
case PrimitiveTypeCode.UInt32:
case PrimitiveTypeCode.Int64:
case PrimitiveTypeCode.UInt64:
return true;
default:
return false;
@@ -25,15 +25,13 @@
using System;
using System.Collections.Generic;
using System.Numerics;
using System.Reflection;
using System.Collections;
using System.Globalization;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Text;
#if NETFX_CORE
using IConvertible = Newtonsoft.Json.Utilities.Convertible;
#endif
#if NETFX_CORE || PORTABLE
using ICustomAttributeProvider = Newtonsoft.Json.Utilities.CustomAttributeProvider;
#endif
@@ -70,29 +68,6 @@ namespace Newtonsoft.Json.Utilities
get { return _underlyingObject; }
}
}
#endif
#if (NETFX_CORE || PORTABLE)
internal enum TypeCode
{
Empty,
Object,
String,
Char,
Boolean,
SByte,
Int16,
UInt16,
Int32,
Byte,
UInt32,
Int64,
UInt64,
Single,
Double,
DateTime,
Decimal
}
[Flags]
internal enum BindingFlags
@@ -985,37 +960,35 @@ namespace Newtonsoft.Json.Utilities
switch (ConvertUtils.GetTypeCode(type))
{
case TypeCode.Boolean:
case PrimitiveTypeCode.Boolean:
return false;
case TypeCode.Char:
case TypeCode.SByte:
case TypeCode.Byte:
case TypeCode.Int16:
case TypeCode.UInt16:
case TypeCode.Int32:
case TypeCode.UInt32:
case PrimitiveTypeCode.Char:
case PrimitiveTypeCode.SByte:
case PrimitiveTypeCode.Byte:
case PrimitiveTypeCode.Int16:
case PrimitiveTypeCode.UInt16:
case PrimitiveTypeCode.Int32:
case PrimitiveTypeCode.UInt32:
return 0;
case TypeCode.Int64:
case TypeCode.UInt64:
case PrimitiveTypeCode.Int64:
case PrimitiveTypeCode.UInt64:
return 0L;
case TypeCode.Single:
case PrimitiveTypeCode.Single:
return 0f;
case TypeCode.Double:
case PrimitiveTypeCode.Double:
return 0.0;
case TypeCode.Decimal:
case PrimitiveTypeCode.Decimal:
return 0m;
case TypeCode.DateTime:
case PrimitiveTypeCode.DateTime:
return new DateTime();
case PrimitiveTypeCode.BigInteger:
return new BigInteger();
case PrimitiveTypeCode.Guid:
return new Guid();
case PrimitiveTypeCode.DateTimeOffset:
return new DateTimeOffset();
}
if (type == typeof(Guid))
return new Guid();
#if !NET20
if (type == typeof(DateTimeOffset))
return new DateTimeOffset();
#endif
if (IsNullable(type))
return null;