diff --git a/Src/Newtonsoft.Json.Tests/Issues/Issue1460.cs b/Src/Newtonsoft.Json.Tests/Issues/Issue1460.cs index fa4340f5..52f32a3f 100644 --- a/Src/Newtonsoft.Json.Tests/Issues/Issue1460.cs +++ b/Src/Newtonsoft.Json.Tests/Issues/Issue1460.cs @@ -30,6 +30,10 @@ using System.Globalization; using System.IO; using System.Linq; using System.Text; +using System.Threading; +#if !(NET20 || NET35 || NET40 || PORTABLE40) +using System.Threading.Tasks; +#endif using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System.Xml; @@ -60,5 +64,17 @@ namespace Newtonsoft.Json.Tests.Issues Assert.AreEqual("null", sw.ToString()); } + +#if !(NET20 || NET35 || NET40 || PORTABLE40) + [Test] + public async Task TestAsync() + { + StringWriter sw = new StringWriter(); + JsonTextWriter writer = new JsonTextWriter(sw); + await JsonWriter.WriteValueAsync(writer, PrimitiveTypeCode.Object, null, CancellationToken.None); + + Assert.AreEqual("null", sw.ToString()); + } +#endif } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/JsonWriter.Async.cs b/Src/Newtonsoft.Json/JsonWriter.Async.cs index 95ec15e5..f7adefc3 100644 --- a/Src/Newtonsoft.Json/JsonWriter.Async.cs +++ b/Src/Newtonsoft.Json/JsonWriter.Async.cs @@ -1680,114 +1680,122 @@ namespace Newtonsoft.Json internal static Task WriteValueAsync(JsonWriter writer, PrimitiveTypeCode typeCode, object value, CancellationToken cancellationToken) { - switch (typeCode) + while (true) { - case PrimitiveTypeCode.Char: - return writer.WriteValueAsync((char)value, cancellationToken); - case PrimitiveTypeCode.CharNullable: - return writer.WriteValueAsync(value == null ? (char?)null : (char)value, cancellationToken); - case PrimitiveTypeCode.Boolean: - return writer.WriteValueAsync((bool)value, cancellationToken); - case PrimitiveTypeCode.BooleanNullable: - return writer.WriteValueAsync(value == null ? (bool?)null : (bool)value, cancellationToken); - case PrimitiveTypeCode.SByte: - return writer.WriteValueAsync((sbyte)value, cancellationToken); - case PrimitiveTypeCode.SByteNullable: - return writer.WriteValueAsync(value == null ? (sbyte?)null : (sbyte)value, cancellationToken); - case PrimitiveTypeCode.Int16: - return writer.WriteValueAsync((short)value, cancellationToken); - case PrimitiveTypeCode.Int16Nullable: - return writer.WriteValueAsync(value == null ? (short?)null : (short)value, cancellationToken); - case PrimitiveTypeCode.UInt16: - return writer.WriteValueAsync((ushort)value, cancellationToken); - case PrimitiveTypeCode.UInt16Nullable: - return writer.WriteValueAsync(value == null ? (ushort?)null : (ushort)value, cancellationToken); - case PrimitiveTypeCode.Int32: - return writer.WriteValueAsync((int)value, cancellationToken); - case PrimitiveTypeCode.Int32Nullable: - return writer.WriteValueAsync(value == null ? (int?)null : (int)value, cancellationToken); - case PrimitiveTypeCode.Byte: - return writer.WriteValueAsync((byte)value, cancellationToken); - case PrimitiveTypeCode.ByteNullable: - return writer.WriteValueAsync(value == null ? (byte?)null : (byte)value, cancellationToken); - case PrimitiveTypeCode.UInt32: - return writer.WriteValueAsync((uint)value, cancellationToken); - case PrimitiveTypeCode.UInt32Nullable: - return writer.WriteValueAsync(value == null ? (uint?)null : (uint)value, cancellationToken); - case PrimitiveTypeCode.Int64: - return writer.WriteValueAsync((long)value, cancellationToken); - case PrimitiveTypeCode.Int64Nullable: - return writer.WriteValueAsync(value == null ? (long?)null : (long)value, cancellationToken); - case PrimitiveTypeCode.UInt64: - return writer.WriteValueAsync((ulong)value, cancellationToken); - case PrimitiveTypeCode.UInt64Nullable: - return writer.WriteValueAsync(value == null ? (ulong?)null : (ulong)value, cancellationToken); - case PrimitiveTypeCode.Single: - return writer.WriteValueAsync((float)value, cancellationToken); - case PrimitiveTypeCode.SingleNullable: - return writer.WriteValueAsync(value == null ? (float?)null : (float)value, cancellationToken); - case PrimitiveTypeCode.Double: - return writer.WriteValueAsync((double)value, cancellationToken); - case PrimitiveTypeCode.DoubleNullable: - return writer.WriteValueAsync(value == null ? (double?)null : (double)value, cancellationToken); - case PrimitiveTypeCode.DateTime: - return writer.WriteValueAsync((DateTime)value, cancellationToken); - case PrimitiveTypeCode.DateTimeNullable: - return writer.WriteValueAsync(value == null ? (DateTime?)null : (DateTime)value, cancellationToken); - case PrimitiveTypeCode.DateTimeOffset: - return writer.WriteValueAsync((DateTimeOffset)value, cancellationToken); - case PrimitiveTypeCode.DateTimeOffsetNullable: - return writer.WriteValueAsync(value == null ? (DateTimeOffset?)null : (DateTimeOffset)value, cancellationToken); - case PrimitiveTypeCode.Decimal: - return writer.WriteValueAsync((decimal)value, cancellationToken); - case PrimitiveTypeCode.DecimalNullable: - return writer.WriteValueAsync(value == null ? (decimal?)null : (decimal)value, cancellationToken); - case PrimitiveTypeCode.Guid: - return writer.WriteValueAsync((Guid)value, cancellationToken); - case PrimitiveTypeCode.GuidNullable: - return writer.WriteValueAsync(value == null ? (Guid?)null : (Guid)value, cancellationToken); - case PrimitiveTypeCode.TimeSpan: - return writer.WriteValueAsync((TimeSpan)value, cancellationToken); - case PrimitiveTypeCode.TimeSpanNullable: - return writer.WriteValueAsync(value == null ? (TimeSpan?)null : (TimeSpan)value, cancellationToken); + switch (typeCode) + { + case PrimitiveTypeCode.Char: + return writer.WriteValueAsync((char)value, cancellationToken); + case PrimitiveTypeCode.CharNullable: + return writer.WriteValueAsync(value == null ? (char?)null : (char)value, cancellationToken); + case PrimitiveTypeCode.Boolean: + return writer.WriteValueAsync((bool)value, cancellationToken); + case PrimitiveTypeCode.BooleanNullable: + return writer.WriteValueAsync(value == null ? (bool?)null : (bool)value, cancellationToken); + case PrimitiveTypeCode.SByte: + return writer.WriteValueAsync((sbyte)value, cancellationToken); + case PrimitiveTypeCode.SByteNullable: + return writer.WriteValueAsync(value == null ? (sbyte?)null : (sbyte)value, cancellationToken); + case PrimitiveTypeCode.Int16: + return writer.WriteValueAsync((short)value, cancellationToken); + case PrimitiveTypeCode.Int16Nullable: + return writer.WriteValueAsync(value == null ? (short?)null : (short)value, cancellationToken); + case PrimitiveTypeCode.UInt16: + return writer.WriteValueAsync((ushort)value, cancellationToken); + case PrimitiveTypeCode.UInt16Nullable: + return writer.WriteValueAsync(value == null ? (ushort?)null : (ushort)value, cancellationToken); + case PrimitiveTypeCode.Int32: + return writer.WriteValueAsync((int)value, cancellationToken); + case PrimitiveTypeCode.Int32Nullable: + return writer.WriteValueAsync(value == null ? (int?)null : (int)value, cancellationToken); + case PrimitiveTypeCode.Byte: + return writer.WriteValueAsync((byte)value, cancellationToken); + case PrimitiveTypeCode.ByteNullable: + return writer.WriteValueAsync(value == null ? (byte?)null : (byte)value, cancellationToken); + case PrimitiveTypeCode.UInt32: + return writer.WriteValueAsync((uint)value, cancellationToken); + case PrimitiveTypeCode.UInt32Nullable: + return writer.WriteValueAsync(value == null ? (uint?)null : (uint)value, cancellationToken); + case PrimitiveTypeCode.Int64: + return writer.WriteValueAsync((long)value, cancellationToken); + case PrimitiveTypeCode.Int64Nullable: + return writer.WriteValueAsync(value == null ? (long?)null : (long)value, cancellationToken); + case PrimitiveTypeCode.UInt64: + return writer.WriteValueAsync((ulong)value, cancellationToken); + case PrimitiveTypeCode.UInt64Nullable: + return writer.WriteValueAsync(value == null ? (ulong?)null : (ulong)value, cancellationToken); + case PrimitiveTypeCode.Single: + return writer.WriteValueAsync((float)value, cancellationToken); + case PrimitiveTypeCode.SingleNullable: + return writer.WriteValueAsync(value == null ? (float?)null : (float)value, cancellationToken); + case PrimitiveTypeCode.Double: + return writer.WriteValueAsync((double)value, cancellationToken); + case PrimitiveTypeCode.DoubleNullable: + return writer.WriteValueAsync(value == null ? (double?)null : (double)value, cancellationToken); + case PrimitiveTypeCode.DateTime: + return writer.WriteValueAsync((DateTime)value, cancellationToken); + case PrimitiveTypeCode.DateTimeNullable: + return writer.WriteValueAsync(value == null ? (DateTime?)null : (DateTime)value, cancellationToken); + case PrimitiveTypeCode.DateTimeOffset: + return writer.WriteValueAsync((DateTimeOffset)value, cancellationToken); + case PrimitiveTypeCode.DateTimeOffsetNullable: + return writer.WriteValueAsync(value == null ? (DateTimeOffset?)null : (DateTimeOffset)value, cancellationToken); + case PrimitiveTypeCode.Decimal: + return writer.WriteValueAsync((decimal)value, cancellationToken); + case PrimitiveTypeCode.DecimalNullable: + return writer.WriteValueAsync(value == null ? (decimal?)null : (decimal)value, cancellationToken); + case PrimitiveTypeCode.Guid: + return writer.WriteValueAsync((Guid)value, cancellationToken); + case PrimitiveTypeCode.GuidNullable: + return writer.WriteValueAsync(value == null ? (Guid?)null : (Guid)value, cancellationToken); + case PrimitiveTypeCode.TimeSpan: + return writer.WriteValueAsync((TimeSpan)value, cancellationToken); + case PrimitiveTypeCode.TimeSpanNullable: + return writer.WriteValueAsync(value == null ? (TimeSpan?)null : (TimeSpan)value, cancellationToken); #if HAVE_BIG_INTEGER - case PrimitiveTypeCode.BigInteger: + case PrimitiveTypeCode.BigInteger: - // this will call to WriteValueAsync(object) - return writer.WriteValueAsync((BigInteger)value, cancellationToken); - case PrimitiveTypeCode.BigIntegerNullable: + // this will call to WriteValueAsync(object) + return writer.WriteValueAsync((BigInteger)value, cancellationToken); + case PrimitiveTypeCode.BigIntegerNullable: - // this will call to WriteValueAsync(object) - return writer.WriteValueAsync(value == null ? (BigInteger?)null : (BigInteger)value, cancellationToken); + // this will call to WriteValueAsync(object) + return writer.WriteValueAsync(value == null ? (BigInteger?)null : (BigInteger)value, cancellationToken); #endif - case PrimitiveTypeCode.Uri: - return writer.WriteValueAsync((Uri)value, cancellationToken); - case PrimitiveTypeCode.String: - return writer.WriteValueAsync((string)value, cancellationToken); - case PrimitiveTypeCode.Bytes: - return writer.WriteValueAsync((byte[])value, cancellationToken); + case PrimitiveTypeCode.Uri: + return writer.WriteValueAsync((Uri)value, cancellationToken); + case PrimitiveTypeCode.String: + return writer.WriteValueAsync((string)value, cancellationToken); + case PrimitiveTypeCode.Bytes: + return writer.WriteValueAsync((byte[])value, cancellationToken); #if HAVE_DB_NULL_TYPE_CODE - case PrimitiveTypeCode.DBNull: - return writer.WriteNullAsync(cancellationToken); + case PrimitiveTypeCode.DBNull: + return writer.WriteNullAsync(cancellationToken); #endif - default: + default: #if HAVE_ICONVERTIBLE - if (value is IConvertible convertable) - { - // the value is a non-standard IConvertible - // convert to the underlying value and retry - TypeInformation typeInformation = ConvertUtils.GetTypeInformation(convertable); + if (value is IConvertible convertible) + { + // the value is a non-standard IConvertible + // convert to the underlying value and retry + TypeInformation typeInformation = ConvertUtils.GetTypeInformation(convertible); - // if convertible has an underlying typecode of Object then attempt to convert it to a string - PrimitiveTypeCode resolvedTypeCode = typeInformation.TypeCode == PrimitiveTypeCode.Object ? PrimitiveTypeCode.String : typeInformation.TypeCode; - Type resolvedType = typeInformation.TypeCode == PrimitiveTypeCode.Object ? typeof(string) : typeInformation.Type; - - object convertedValue = convertable.ToType(resolvedType, CultureInfo.InvariantCulture); - - return WriteValueAsync(writer, resolvedTypeCode, convertedValue, cancellationToken); - } + // if convertible has an underlying typecode of Object then attempt to convert it to a string + typeCode = typeInformation.TypeCode == PrimitiveTypeCode.Object ? PrimitiveTypeCode.String : typeInformation.TypeCode; + Type resolvedType = typeInformation.TypeCode == PrimitiveTypeCode.Object ? typeof(string) : typeInformation.Type; + value = convertible.ToType(resolvedType, CultureInfo.InvariantCulture); + continue; + } #endif - throw CreateUnsupportedTypeException(writer, value); + + // write an unknown null value, fix https://github.com/JamesNK/Newtonsoft.Json/issues/1460 + if (value == null) + { + return writer.WriteNullAsync(cancellationToken); + } + + throw CreateUnsupportedTypeException(writer, value); + } } } } diff --git a/Src/Newtonsoft.Json/JsonWriter.cs b/Src/Newtonsoft.Json/JsonWriter.cs index f3df862d..b398a011 100644 --- a/Src/Newtonsoft.Json/JsonWriter.cs +++ b/Src/Newtonsoft.Json/JsonWriter.cs @@ -1482,163 +1482,200 @@ namespace Newtonsoft.Json internal static void WriteValue(JsonWriter writer, PrimitiveTypeCode typeCode, object value) { - switch (typeCode) + while (true) { - 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; + switch (typeCode) + { + case PrimitiveTypeCode.Char: + writer.WriteValue((char)value); + return; + + case PrimitiveTypeCode.CharNullable: + writer.WriteValue((value == null) ? (char?)null : (char)value); + return; + + case PrimitiveTypeCode.Boolean: + writer.WriteValue((bool)value); + return; + + case PrimitiveTypeCode.BooleanNullable: + writer.WriteValue((value == null) ? (bool?)null : (bool)value); + return; + + case PrimitiveTypeCode.SByte: + writer.WriteValue((sbyte)value); + return; + + case PrimitiveTypeCode.SByteNullable: + writer.WriteValue((value == null) ? (sbyte?)null : (sbyte)value); + return; + + case PrimitiveTypeCode.Int16: + writer.WriteValue((short)value); + return; + + case PrimitiveTypeCode.Int16Nullable: + writer.WriteValue((value == null) ? (short?)null : (short)value); + return; + + case PrimitiveTypeCode.UInt16: + writer.WriteValue((ushort)value); + return; + + case PrimitiveTypeCode.UInt16Nullable: + writer.WriteValue((value == null) ? (ushort?)null : (ushort)value); + return; + + case PrimitiveTypeCode.Int32: + writer.WriteValue((int)value); + return; + + case PrimitiveTypeCode.Int32Nullable: + writer.WriteValue((value == null) ? (int?)null : (int)value); + return; + + case PrimitiveTypeCode.Byte: + writer.WriteValue((byte)value); + return; + + case PrimitiveTypeCode.ByteNullable: + writer.WriteValue((value == null) ? (byte?)null : (byte)value); + return; + + case PrimitiveTypeCode.UInt32: + writer.WriteValue((uint)value); + return; + + case PrimitiveTypeCode.UInt32Nullable: + writer.WriteValue((value == null) ? (uint?)null : (uint)value); + return; + + case PrimitiveTypeCode.Int64: + writer.WriteValue((long)value); + return; + + case PrimitiveTypeCode.Int64Nullable: + writer.WriteValue((value == null) ? (long?)null : (long)value); + return; + + case PrimitiveTypeCode.UInt64: + writer.WriteValue((ulong)value); + return; + + case PrimitiveTypeCode.UInt64Nullable: + writer.WriteValue((value == null) ? (ulong?)null : (ulong)value); + return; + + case PrimitiveTypeCode.Single: + writer.WriteValue((float)value); + return; + + case PrimitiveTypeCode.SingleNullable: + writer.WriteValue((value == null) ? (float?)null : (float)value); + return; + + case PrimitiveTypeCode.Double: + writer.WriteValue((double)value); + return; + + case PrimitiveTypeCode.DoubleNullable: + writer.WriteValue((value == null) ? (double?)null : (double)value); + return; + + case PrimitiveTypeCode.DateTime: + writer.WriteValue((DateTime)value); + return; + + case PrimitiveTypeCode.DateTimeNullable: + writer.WriteValue((value == null) ? (DateTime?)null : (DateTime)value); + return; + #if HAVE_DATE_TIME_OFFSET - case PrimitiveTypeCode.DateTimeOffset: - writer.WriteValue((DateTimeOffset)value); - break; - case PrimitiveTypeCode.DateTimeOffsetNullable: - writer.WriteValue((value == null) ? (DateTimeOffset?)null : (DateTimeOffset)value); - break; + case PrimitiveTypeCode.DateTimeOffset: + writer.WriteValue((DateTimeOffset)value); + return; + + case PrimitiveTypeCode.DateTimeOffsetNullable: + writer.WriteValue((value == null) ? (DateTimeOffset?)null : (DateTimeOffset)value); + return; #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; + case PrimitiveTypeCode.Decimal: + writer.WriteValue((decimal)value); + return; + + case PrimitiveTypeCode.DecimalNullable: + writer.WriteValue((value == null) ? (decimal?)null : (decimal)value); + break; + case PrimitiveTypeCode.Guid: + writer.WriteValue((Guid)value); + return; + + case PrimitiveTypeCode.GuidNullable: + writer.WriteValue((value == null) ? (Guid?)null : (Guid)value); + return; + + case PrimitiveTypeCode.TimeSpan: + writer.WriteValue((TimeSpan)value); + return; + + case PrimitiveTypeCode.TimeSpanNullable: + writer.WriteValue((value == null) ? (TimeSpan?)null : (TimeSpan)value); + return; + #if HAVE_BIG_INTEGER - case PrimitiveTypeCode.BigInteger: - // this will call to WriteValue(object) - writer.WriteValue((BigInteger)value); - break; - case PrimitiveTypeCode.BigIntegerNullable: - // this will call to WriteValue(object) - writer.WriteValue((value == null) ? (BigInteger?)null : (BigInteger)value); - break; + case PrimitiveTypeCode.BigInteger: + // this will call to WriteValue(object) + writer.WriteValue((BigInteger)value); + return; + + case PrimitiveTypeCode.BigIntegerNullable: + // this will call to WriteValue(object) + writer.WriteValue((value == null) ? (BigInteger?)null : (BigInteger)value); + return; #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; + case PrimitiveTypeCode.Uri: + writer.WriteValue((Uri)value); + return; + + case PrimitiveTypeCode.String: + writer.WriteValue((string)value); + return; + + case PrimitiveTypeCode.Bytes: + writer.WriteValue((byte[])value); + return; + #if HAVE_DB_NULL_TYPE_CODE - case PrimitiveTypeCode.DBNull: - writer.WriteNull(); - break; -#endif - default: -#if HAVE_ICONVERTIBLE - if (value is IConvertible convertible) - { - // the value is a non-standard IConvertible - // convert to the underlying value and retry - - TypeInformation typeInformation = ConvertUtils.GetTypeInformation(convertible); - - // if convertible has an underlying typecode of Object then attempt to convert it to a string - PrimitiveTypeCode resolvedTypeCode = (typeInformation.TypeCode == PrimitiveTypeCode.Object) ? PrimitiveTypeCode.String : typeInformation.TypeCode; - Type resolvedType = (typeInformation.TypeCode == PrimitiveTypeCode.Object) ? typeof(string) : typeInformation.Type; - - object convertedValue = convertible.ToType(resolvedType, CultureInfo.InvariantCulture); - - WriteValue(writer, resolvedTypeCode, convertedValue); - break; - } -#endif - // write an unknown null value, fix https://github.com/JamesNK/Newtonsoft.Json/issues/1460 - if (value == null) - { + case PrimitiveTypeCode.DBNull: writer.WriteNull(); - break; - } + return; +#endif + default: +#if HAVE_ICONVERTIBLE + if (value is IConvertible convertible) + { + // the value is a non-standard IConvertible + // convert to the underlying value and retry - throw CreateUnsupportedTypeException(writer, value); + TypeInformation typeInformation = ConvertUtils.GetTypeInformation(convertible); + + // if convertible has an underlying typecode of Object then attempt to convert it to a string + typeCode = typeInformation.TypeCode == PrimitiveTypeCode.Object ? PrimitiveTypeCode.String : typeInformation.TypeCode; + Type resolvedType = typeInformation.TypeCode == PrimitiveTypeCode.Object ? typeof(string) : typeInformation.Type; + value = convertible.ToType(resolvedType, CultureInfo.InvariantCulture); + continue; + } +#endif + + // write an unknown null value, fix https://github.com/JamesNK/Newtonsoft.Json/issues/1460 + if (value == null) + { + writer.WriteNull(); + return; + } + + throw CreateUnsupportedTypeException(writer, value); + } } } diff --git a/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs b/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs index 0e0def46..b49df890 100644 --- a/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs +++ b/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs @@ -353,24 +353,20 @@ namespace Newtonsoft.Json.Utilities private static bool InheritsGenericDefinitionInternal(Type currentType, Type genericClassDefinition, out Type implementingType) { - if (currentType.IsGenericType()) + do { - Type currentGenericClassDefinition = currentType.GetGenericTypeDefinition(); - - if (genericClassDefinition == currentGenericClassDefinition) + if (currentType.IsGenericType() && genericClassDefinition == currentType.GetGenericTypeDefinition()) { implementingType = currentType; return true; } - } - if (currentType.BaseType() == null) - { - implementingType = null; - return false; + currentType = currentType.BaseType(); } + while (currentType != null); - return InheritsGenericDefinitionInternal(currentType.BaseType(), genericClassDefinition, out implementingType); + implementingType = null; + return false; } ///