From 08c7055d9187cdd5bac8ef3d26d0733709bd55b1 Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Sun, 31 Mar 2013 18:36:09 +1300 Subject: [PATCH] -Performance? --- .../Converters/RegexConverter.cs | 2 +- Src/Newtonsoft.Json/JsonWriter.cs | 17 +- .../Serialization/JsonPrimitiveContract.cs | 308 +++++++++++++++++- .../JsonSerializerInternalWriter.cs | 10 +- 4 files changed, 325 insertions(+), 12 deletions(-) diff --git a/Src/Newtonsoft.Json/Converters/RegexConverter.cs b/Src/Newtonsoft.Json/Converters/RegexConverter.cs index dc70c575..cad2481f 100644 --- a/Src/Newtonsoft.Json/Converters/RegexConverter.cs +++ b/Src/Newtonsoft.Json/Converters/RegexConverter.cs @@ -91,7 +91,7 @@ namespace Newtonsoft.Json.Converters writer.WritePropertyName("Pattern"); writer.WriteValue(regex.ToString()); writer.WritePropertyName("Options"); - writer.WriteValue(regex.Options); + writer.WriteValue((int)regex.Options); writer.WriteEndObject(); } diff --git a/Src/Newtonsoft.Json/JsonWriter.cs b/Src/Newtonsoft.Json/JsonWriter.cs index 38a309e1..b4258909 100644 --- a/Src/Newtonsoft.Json/JsonWriter.cs +++ b/Src/Newtonsoft.Json/JsonWriter.cs @@ -1234,6 +1234,18 @@ namespace Newtonsoft.Json { InternalWriteValue(JsonToken.Integer); } + + /// + /// Writes a value. + /// + /// The value to write. + public virtual void WriteValue(BigInteger? value) + { + if (value == null) + WriteNull(); + else + WriteValue(value.Value); + } #endif /// @@ -1403,7 +1415,10 @@ namespace Newtonsoft.Json #if !(NET20 || NET35 || SILVERLIGHT || PORTABLE) else if (value is BigInteger) { - WriteValue((BigInteger)value); + if (nullable) + WriteValue((BigInteger?)value); + else + WriteValue((BigInteger)value); return; } #endif diff --git a/Src/Newtonsoft.Json/Serialization/JsonPrimitiveContract.cs b/Src/Newtonsoft.Json/Serialization/JsonPrimitiveContract.cs index f3ff93b5..23bdbc9d 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonPrimitiveContract.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonPrimitiveContract.cs @@ -24,6 +24,10 @@ #endregion using System; +using System.Collections.Generic; +#if !(PORTABLE || NET35 || NET20 || WINDOWS_PHONE || SILVERLIGHT) +using System.Numerics; +#endif using Newtonsoft.Json.Utilities; namespace Newtonsoft.Json.Serialization @@ -33,7 +37,58 @@ namespace Newtonsoft.Json.Serialization /// public class JsonPrimitiveContract : JsonContract { - internal bool Nullable { get; set; } + private static readonly Dictionary TypeCodeMap = + new Dictionary + { + { 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; } /// /// Initializes a new instance of the class. @@ -44,7 +99,256 @@ namespace Newtonsoft.Json.Serialization { ContractType = JsonContractType.Primitive; - Nullable = ReflectionUtils.IsNullable(underlyingType); + // 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; + } + + 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 + } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs index 02b9d0c9..05b833f0 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs @@ -94,20 +94,14 @@ namespace Newtonsoft.Json.Serialization WriteTypeProperty(writer, contract.CreatedType); writer.WritePropertyName(JsonTypeReflector.ValuePropertyName); - if (contract.IsNullable) - writer.WriteValue(value, true); - else - writer.WriteValue(value); + contract.WriteValue(writer, value); writer.WriteEndObject(); return; } } - if (contract.IsNullable) - writer.WriteValue(value, true); - else - writer.WriteValue(value); + contract.WriteValue(writer, value); } private void SerializeValue(JsonWriter writer, object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)