From 500440e04f744af6eed8c54715043a5785bc4d78 Mon Sep 17 00:00:00 2001 From: JamesNK Date: Wed, 24 Sep 2008 09:39:30 +0000 Subject: [PATCH] -Added nullable DateTime support to IsoDateTimeConverter and JavaScriptDateTimeConverter -Added WriteValue overloads to JsonWriter for nullable types -Fixed JsonTextWriter.WriteValue(string) to write null instead of an empty string for a null value -Fixed JsonWriter.WriteValue(object) to no longer error on null values --- .../Converters/IsoDateTimeConverterTests.cs | 48 +++++ .../JavaScriptDateTimeConverterTests.cs | 34 ++++ .../JsonSerializerTest.cs | 8 +- .../JsonTextWriterTest.cs | 83 +++++++- .../JsonTokenWriterTest.cs | 2 +- .../Newtonsoft.Json.Tests.Compact.csproj | 1 + .../Newtonsoft.Json.Tests.Silverlight.csproj | 1 + .../Newtonsoft.Json.Tests.csproj | 1 + .../NullableDateTimeTestClass.cs | 40 ++++ .../Converters/IsoDateTimeConverter.cs | 22 ++- .../Converters/JavaScriptDateTimeConverter.cs | 18 +- Src/Newtonsoft.Json/JsonTextWriter.cs | 2 +- Src/Newtonsoft.Json/JsonWriter.cs | 181 ++++++++++++++++++ 13 files changed, 431 insertions(+), 10 deletions(-) create mode 100644 Src/Newtonsoft.Json.Tests/NullableDateTimeTestClass.cs diff --git a/Src/Newtonsoft.Json.Tests/Converters/IsoDateTimeConverterTests.cs b/Src/Newtonsoft.Json.Tests/Converters/IsoDateTimeConverterTests.cs index 5ee894a8..cdbd5d72 100644 --- a/Src/Newtonsoft.Json.Tests/Converters/IsoDateTimeConverterTests.cs +++ b/Src/Newtonsoft.Json.Tests/Converters/IsoDateTimeConverterTests.cs @@ -174,6 +174,26 @@ namespace Newtonsoft.Json.Tests.Converters Assert.AreEqual(@"{""PreField"":""Pre"",""DateTimeField"":""2008-01-01T01:01:01.0000000Z"",""DateTimeOffsetField"":""2008-01-01T01:01:01.0000000+00:00"",""PostField"":""Post""}", json); } + [Test] + public void NullableSerializeUTC() + { + NullableDateTimeTestClass c = new NullableDateTimeTestClass(); + c.DateTimeField = new DateTime(2008, 12, 12, 12, 12, 12, 0, DateTimeKind.Utc).ToLocalTime(); + c.DateTimeOffsetField = new DateTime(2008, 12, 12, 12, 12, 12, 0, DateTimeKind.Utc).ToLocalTime(); + c.PreField = "Pre"; + c.PostField = "Post"; + string json = JavaScriptConvert.SerializeObject(c, new IsoDateTimeConverter() { DateTimeStyles = DateTimeStyles.AssumeUniversal }); + Assert.AreEqual(@"{""PreField"":""Pre"",""DateTimeField"":""2008-12-12T12:12:12.0000000Z"",""DateTimeOffsetField"":""2008-12-12T12:12:12.0000000+00:00"",""PostField"":""Post""}", json); + + //test the other edge case too + c.DateTimeField = null; + c.DateTimeOffsetField = null; + c.PreField = "Pre"; + c.PostField = "Post"; + json = JavaScriptConvert.SerializeObject(c, new IsoDateTimeConverter() { DateTimeStyles = DateTimeStyles.AssumeUniversal }); + Assert.AreEqual(@"{""PreField"":""Pre"",""DateTimeField"":null,""DateTimeOffsetField"":null,""PostField"":""Post""}", json); + } + [Test] public void DeserializeUTC() { @@ -194,6 +214,34 @@ namespace Newtonsoft.Json.Tests.Converters Assert.AreEqual("Post", c2.PostField); } + [Test] + public void NullableDeserializeUTC() + { + NullableDateTimeTestClass c = + JavaScriptConvert.DeserializeObject(@"{""PreField"":""Pre"",""DateTimeField"":""2008-12-12T12:12:12Z"",""DateTimeOffsetField"":""2008-12-12T12:12:12Z"",""PostField"":""Post""}", new IsoDateTimeConverter() { DateTimeStyles = DateTimeStyles.AssumeUniversal }); + + Assert.AreEqual(new DateTime(2008, 12, 12, 12, 12, 12, 0, DateTimeKind.Utc).ToLocalTime(), c.DateTimeField); + Assert.AreEqual(new DateTimeOffset(2008, 12, 12, 12, 12, 12, 0, TimeSpan.Zero), c.DateTimeOffsetField); + Assert.AreEqual("Pre", c.PreField); + Assert.AreEqual("Post", c.PostField); + + NullableDateTimeTestClass c2 = + JavaScriptConvert.DeserializeObject(@"{""PreField"":""Pre"",""DateTimeField"":null,""DateTimeOffsetField"":null,""PostField"":""Post""}", new IsoDateTimeConverter() { DateTimeStyles = DateTimeStyles.AssumeUniversal }); + + Assert.AreEqual(null, c2.DateTimeField); + Assert.AreEqual(null, c2.DateTimeOffsetField); + Assert.AreEqual("Pre", c2.PreField); + Assert.AreEqual("Post", c2.PostField); + } + + [Test] + [ExpectedException(typeof(Exception), ExpectedMessage = "Cannot convert null value to System.DateTime.")] + public void DeserializeNullToNonNullable() + { + DateTimeTestClass c2 = + JavaScriptConvert.DeserializeObject(@"{""PreField"":""Pre"",""DateTimeField"":null,""DateTimeOffsetField"":null,""PostField"":""Post""}", new IsoDateTimeConverter() { DateTimeStyles = DateTimeStyles.AssumeUniversal }); + } + [Test] public void SerializeShouldChangeNonUTCDates() { diff --git a/Src/Newtonsoft.Json.Tests/Converters/JavaScriptDateTimeConverterTests.cs b/Src/Newtonsoft.Json.Tests/Converters/JavaScriptDateTimeConverterTests.cs index 8c29d71d..c4d27e48 100644 --- a/Src/Newtonsoft.Json.Tests/Converters/JavaScriptDateTimeConverterTests.cs +++ b/Src/Newtonsoft.Json.Tests/Converters/JavaScriptDateTimeConverterTests.cs @@ -58,6 +58,32 @@ namespace Newtonsoft.Json.Tests.Converters Assert.AreEqual("new Date(976918263055)", result); } + [Test] + public void SerializeNullableDateTimeClass() + { + NullableDateTimeTestClass t = new NullableDateTimeTestClass() + { + DateTimeField = null, + DateTimeOffsetField = null + }; + + JavaScriptDateTimeConverter converter = new JavaScriptDateTimeConverter(); + + string result; + + result = JavaScriptConvert.SerializeObject(t, converter); + Assert.AreEqual(@"{""PreField"":null,""DateTimeField"":null,""DateTimeOffsetField"":null,""PostField"":null}", result); + + t = new NullableDateTimeTestClass() + { + DateTimeField = new DateTime(2000, 12, 15, 22, 11, 3, 55, DateTimeKind.Utc), + DateTimeOffsetField = new DateTimeOffset(2000, 12, 15, 22, 11, 3, 55, TimeSpan.Zero) + }; + + result = JavaScriptConvert.SerializeObject(t, converter); + Assert.AreEqual(@"{""PreField"":null,""DateTimeField"":new Date(976918263055),""DateTimeOffsetField"":new Date(976918263055),""PostField"":null}", result); + } + [Test] public void DeserializeDateTime() { @@ -67,6 +93,14 @@ namespace Newtonsoft.Json.Tests.Converters Assert.AreEqual(new DateTime(2000, 12, 15, 22, 11, 3, 55, DateTimeKind.Utc), result); } + [Test] + [ExpectedException(typeof(Exception), ExpectedMessage = "Cannot convert null value to System.DateTime.")] + public void DeserializeNullToNonNullable() + { + DateTimeTestClass c2 = + JavaScriptConvert.DeserializeObject(@"{""PreField"":""Pre"",""DateTimeField"":null,""DateTimeOffsetField"":null,""PostField"":""Post""}", new JavaScriptDateTimeConverter()); + } + [Test] public void DeserializeDateTimeOffset() { diff --git a/Src/Newtonsoft.Json.Tests/JsonSerializerTest.cs b/Src/Newtonsoft.Json.Tests/JsonSerializerTest.cs index 6ad453e4..c2fb5eb2 100644 --- a/Src/Newtonsoft.Json.Tests/JsonSerializerTest.cs +++ b/Src/Newtonsoft.Json.Tests/JsonSerializerTest.cs @@ -1325,11 +1325,15 @@ keyword such as type of business."" } [Test] - public void DeserializeStringDate() + public void DeserializeNullable() { - string dateText = @"""\/Date(1221644506800-0700)\/"""; + string json; + json = JavaScriptConvert.SerializeObject((int?)null); + Assert.AreEqual("null", json); + json = JavaScriptConvert.SerializeObject((int?)1); + Assert.AreEqual("1", json); } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/JsonTextWriterTest.cs b/Src/Newtonsoft.Json.Tests/JsonTextWriterTest.cs index 0cf8f056..169a556c 100644 --- a/Src/Newtonsoft.Json.Tests/JsonTextWriterTest.cs +++ b/Src/Newtonsoft.Json.Tests/JsonTextWriterTest.cs @@ -51,14 +51,15 @@ namespace Newtonsoft.Json.Tests jsonWriter.WriteValue(0.99); jsonWriter.WriteValue(0.000000000000000001d); jsonWriter.WriteValue(0.000000000000000001m); - jsonWriter.WriteValue(null); + jsonWriter.WriteValue((string)null); + jsonWriter.WriteValue((object)null); jsonWriter.WriteValue("This is a string."); jsonWriter.WriteNull(); jsonWriter.WriteUndefined(); jsonWriter.WriteEndArray(); } - string expected = @"[""@"",""\r\n\t\f\b?{\\r\\n\""'"",true,10,10.99,0.99,1E-18,0.000000000000000001,"""",""This is a string."",null,undefined]"; + string expected = @"[""@"",""\r\n\t\f\b?{\\r\\n\""'"",true,10,10.99,0.99,1E-18,0.000000000000000001,null,null,""This is a string."",null,undefined]"; string result = sb.ToString(); Console.WriteLine("ValueFormatting"); @@ -67,6 +68,84 @@ namespace Newtonsoft.Json.Tests Assert.AreEqual(expected, result); } + [Test] + public void NullableValueFormatting() + { + StringWriter sw = new StringWriter(); + using (JsonTextWriter jsonWriter = new JsonTextWriter(sw)) + { + jsonWriter.WriteStartArray(); + jsonWriter.WriteValue((char?)null); + jsonWriter.WriteValue((char?)'c'); + jsonWriter.WriteValue((bool?)null); + jsonWriter.WriteValue((bool?)true); + jsonWriter.WriteValue((byte?)null); + jsonWriter.WriteValue((byte?)1); + jsonWriter.WriteValue((sbyte?)null); + jsonWriter.WriteValue((sbyte?)1); + jsonWriter.WriteValue((short?)null); + jsonWriter.WriteValue((short?)1); + jsonWriter.WriteValue((ushort?)null); + jsonWriter.WriteValue((ushort?)1); + jsonWriter.WriteValue((int?)null); + jsonWriter.WriteValue((int?)1); + jsonWriter.WriteValue((uint?)null); + jsonWriter.WriteValue((uint?)1); + jsonWriter.WriteValue((long?)null); + jsonWriter.WriteValue((long?)1); + jsonWriter.WriteValue((ulong?)null); + jsonWriter.WriteValue((ulong?)1); + jsonWriter.WriteValue((double?)null); + jsonWriter.WriteValue((double?)1.1); + jsonWriter.WriteValue((float?)null); + jsonWriter.WriteValue((float?)1.1); + jsonWriter.WriteValue((decimal?)null); + jsonWriter.WriteValue((decimal?)1.1m); + jsonWriter.WriteValue((DateTime?)null); + jsonWriter.WriteValue((DateTime?)new DateTime(JavaScriptConvert.InitialJavaScriptDateTicks, DateTimeKind.Utc)); + jsonWriter.WriteValue((DateTimeOffset?)null); + jsonWriter.WriteValue((DateTimeOffset?)new DateTimeOffset(JavaScriptConvert.InitialJavaScriptDateTicks, TimeSpan.Zero)); + jsonWriter.WriteEndArray(); + } + + string json = sw.ToString(); + string expected = @"[null,""c"",null,true,null,1,null,1,null,1,null,1,null,1,null,1,null,1,null,1,null,1.1,null,1.1,null,1.1,null,""\/Date(0)\/"",null,""\/Date(0+0000)\/""]"; + + Assert.AreEqual(expected, json); + } + + [Test] + public void WriteValueObjectWithNullable() + { + StringWriter sw = new StringWriter(); + using (JsonTextWriter jsonWriter = new JsonTextWriter(sw)) + { + char? value = 'c'; + + jsonWriter.WriteStartArray(); + jsonWriter.WriteValue((object)value); + jsonWriter.WriteEndArray(); + } + + string json = sw.ToString(); + string expected = @"[""c""]"; + + Assert.AreEqual(expected, json); + } + + [Test] + [ExpectedException(typeof(ArgumentException), ExpectedMessage = @"Unsupported type: System.Version. Use the JsonSerializer class to get the object's JSON representation.")] + public void WriteValueObjectWithUnsupportedValue() + { + StringWriter sw = new StringWriter(); + using (JsonTextWriter jsonWriter = new JsonTextWriter(sw)) + { + jsonWriter.WriteStartArray(); + jsonWriter.WriteValue(new Version(1, 1, 1, 1)); + jsonWriter.WriteEndArray(); + } + } + [Test] public void StringEscaping() { diff --git a/Src/Newtonsoft.Json.Tests/JsonTokenWriterTest.cs b/Src/Newtonsoft.Json.Tests/JsonTokenWriterTest.cs index 87248bc2..cf454339 100644 --- a/Src/Newtonsoft.Json.Tests/JsonTokenWriterTest.cs +++ b/Src/Newtonsoft.Json.Tests/JsonTokenWriterTest.cs @@ -51,7 +51,7 @@ namespace Newtonsoft.Json.Tests jsonWriter.WriteValue(0.99); jsonWriter.WriteValue(0.000000000000000001d); jsonWriter.WriteValue(0.000000000000000001m); - jsonWriter.WriteValue(null); + jsonWriter.WriteValue((string)null); jsonWriter.WriteValue("This is a string."); jsonWriter.WriteNull(); jsonWriter.WriteUndefined(); diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Compact.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Compact.csproj index bf7ebc84..3bd77122 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Compact.csproj +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Compact.csproj @@ -74,6 +74,7 @@ + diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Silverlight.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Silverlight.csproj index 8dbeac7e..8fc31273 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Silverlight.csproj +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Silverlight.csproj @@ -130,6 +130,7 @@ + diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj index e4c5d2cf..eadb6a8e 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj @@ -73,6 +73,7 @@ + diff --git a/Src/Newtonsoft.Json.Tests/NullableDateTimeTestClass.cs b/Src/Newtonsoft.Json.Tests/NullableDateTimeTestClass.cs new file mode 100644 index 00000000..e619d38b --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/NullableDateTimeTestClass.cs @@ -0,0 +1,40 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Newtonsoft.Json.Tests +{ + public class NullableDateTimeTestClass + { + public string PreField { get; set; } + public DateTime? DateTimeField { get; set; } + public DateTimeOffset? DateTimeOffsetField { get; set; } + public string PostField { get; set; } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Converters/IsoDateTimeConverter.cs b/Src/Newtonsoft.Json/Converters/IsoDateTimeConverter.cs index 7e4ea01a..cc9fc5ca 100644 --- a/Src/Newtonsoft.Json/Converters/IsoDateTimeConverter.cs +++ b/Src/Newtonsoft.Json/Converters/IsoDateTimeConverter.cs @@ -92,12 +92,24 @@ namespace Newtonsoft.Json.Converters /// The object value. public override object ReadJson(JsonReader reader, Type objectType) { + Type t = (ReflectionUtils.IsNullableType(objectType)) + ? Nullable.GetUnderlyingType(objectType) + : objectType; + + if (reader.TokenType == JsonToken.Null) + { + if (!ReflectionUtils.IsNullableType(objectType)) + throw new Exception("Cannot convert null value to {0}.".FormatWith(CultureInfo.InvariantCulture, objectType)); + + return null; + } + if (reader.TokenType != JsonToken.String) throw new Exception("Unexpected token parsing date. Expected String, got {0}.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType)); string dateText = reader.Value.ToString(); - if (objectType == typeof(DateTimeOffset)) + if (t == typeof(DateTimeOffset)) { if (!string.IsNullOrEmpty(_dateTimeFormat)) return DateTimeOffset.ParseExact(dateText, _dateTimeFormat, Culture, _dateTimeStyles); @@ -120,9 +132,13 @@ namespace Newtonsoft.Json.Converters /// public override bool CanConvert(Type objectType) { - if (typeof(DateTime).IsAssignableFrom(objectType)) + Type t = (ReflectionUtils.IsNullableType(objectType)) + ? Nullable.GetUnderlyingType(objectType) + : objectType; + + if (typeof(DateTime).IsAssignableFrom(t)) return true; - if (typeof(DateTimeOffset).IsAssignableFrom(objectType)) + if (typeof(DateTimeOffset).IsAssignableFrom(t)) return true; return false; diff --git a/Src/Newtonsoft.Json/Converters/JavaScriptDateTimeConverter.cs b/Src/Newtonsoft.Json/Converters/JavaScriptDateTimeConverter.cs index e20b2806..410880a4 100644 --- a/Src/Newtonsoft.Json/Converters/JavaScriptDateTimeConverter.cs +++ b/Src/Newtonsoft.Json/Converters/JavaScriptDateTimeConverter.cs @@ -47,6 +47,18 @@ namespace Newtonsoft.Json.Converters /// The object value. public override object ReadJson(JsonReader reader, Type objectType) { + Type t = (ReflectionUtils.IsNullableType(objectType)) + ? Nullable.GetUnderlyingType(objectType) + : objectType; + + if (reader.TokenType == JsonToken.Null) + { + if (!ReflectionUtils.IsNullableType(objectType)) + throw new Exception("Cannot convert null value to {0}.".FormatWith(CultureInfo.InvariantCulture, objectType)); + + return null; + } + if (reader.TokenType != JsonToken.StartConstructor || string.Compare(reader.Value.ToString(), "Date", StringComparison.Ordinal) != 0) throw new Exception("Unexpected token or value when parsing date. Token: {0}, Value: {1}".FormatWith(CultureInfo.InvariantCulture, reader.TokenType, reader.Value)); @@ -64,7 +76,7 @@ namespace Newtonsoft.Json.Converters if (reader.TokenType != JsonToken.EndConstructor) throw new Exception("Unexpected token parsing date. Expected EndConstructor, got {0}.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType)); - if (objectType == typeof(DateTimeOffset)) + if (t == typeof(DateTimeOffset)) return new DateTimeOffset(d); return d; @@ -79,6 +91,10 @@ namespace Newtonsoft.Json.Converters /// public override bool CanConvert(Type objectType) { + Type t = (ReflectionUtils.IsNullableType(objectType)) + ? Nullable.GetUnderlyingType(objectType) + : objectType; + if (typeof(DateTime).IsAssignableFrom(objectType)) return true; if (typeof(DateTimeOffset).IsAssignableFrom(objectType)) diff --git a/Src/Newtonsoft.Json/JsonTextWriter.cs b/Src/Newtonsoft.Json/JsonTextWriter.cs index 040481d6..cd3aa1c2 100644 --- a/Src/Newtonsoft.Json/JsonTextWriter.cs +++ b/Src/Newtonsoft.Json/JsonTextWriter.cs @@ -276,7 +276,7 @@ namespace Newtonsoft.Json public override void WriteValue(string value) { base.WriteValue(value); - WriteValueInternal(JavaScriptConvert.ToString(value, _quoteChar), JsonToken.String); + WriteValueInternal((value != null) ? JavaScriptConvert.ToString(value, _quoteChar) : JavaScriptConvert.Null, JsonToken.String); } /// diff --git a/Src/Newtonsoft.Json/JsonWriter.cs b/Src/Newtonsoft.Json/JsonWriter.cs index 552e5dbc..fce2ffd1 100644 --- a/Src/Newtonsoft.Json/JsonWriter.cs +++ b/Src/Newtonsoft.Json/JsonWriter.cs @@ -737,6 +737,186 @@ namespace Newtonsoft.Json AutoComplete(JsonToken.Date); } + /// + /// Writes a value. + /// + /// The value to write. + public virtual void WriteValue(int? value) + { + if (value == null) + WriteNull(); + else + WriteValue(value.Value); + } + + /// + /// Writes a value. + /// + /// The value to write. + public virtual void WriteValue(uint? value) + { + if (value == null) + WriteNull(); + else + WriteValue(value.Value); + } + + /// + /// Writes a value. + /// + /// The value to write. + public virtual void WriteValue(long? value) + { + if (value == null) + WriteNull(); + else + WriteValue(value.Value); + } + + /// + /// Writes a value. + /// + /// The value to write. + public virtual void WriteValue(ulong? value) + { + if (value == null) + WriteNull(); + else + WriteValue(value.Value); + } + + /// + /// Writes a value. + /// + /// The value to write. + public virtual void WriteValue(float? value) + { + if (value == null) + WriteNull(); + else + WriteValue(value.Value); + } + + /// + /// Writes a value. + /// + /// The value to write. + public virtual void WriteValue(double? value) + { + if (value == null) + WriteNull(); + else + WriteValue(value.Value); + } + + /// + /// Writes a value. + /// + /// The value to write. + public virtual void WriteValue(bool? value) + { + if (value == null) + WriteNull(); + else + WriteValue(value.Value); + } + + /// + /// Writes a value. + /// + /// The value to write. + public virtual void WriteValue(short? value) + { + if (value == null) + WriteNull(); + else + WriteValue(value.Value); + } + + /// + /// Writes a value. + /// + /// The value to write. + public virtual void WriteValue(ushort? value) + { + if (value == null) + WriteNull(); + else + WriteValue(value.Value); + } + + /// + /// Writes a value. + /// + /// The value to write. + public virtual void WriteValue(char? value) + { + if (value == null) + WriteNull(); + else + WriteValue(value.Value); + } + + /// + /// Writes a value. + /// + /// The value to write. + public virtual void WriteValue(byte? value) + { + if (value == null) + WriteNull(); + else + WriteValue(value.Value); + } + + /// + /// Writes a value. + /// + /// The value to write. + public virtual void WriteValue(sbyte? value) + { + if (value == null) + WriteNull(); + else + WriteValue(value.Value); + } + + /// + /// Writes a value. + /// + /// The value to write. + public virtual void WriteValue(decimal? value) + { + if (value == null) + WriteNull(); + else + WriteValue(value.Value); + } + + /// + /// Writes a value. + /// + /// The value to write. + public virtual void WriteValue(DateTime? value) + { + if (value == null) + WriteNull(); + else + WriteValue(value.Value); + } + + /// + /// Writes a value. + /// + /// The value to write. + public virtual void WriteValue(DateTimeOffset? value) + { + if (value == null) + WriteNull(); + else + WriteValue(value.Value); + } + /// /// Writes a value. /// An error will raised if the value cannot be written as a single JSON token. @@ -747,6 +927,7 @@ namespace Newtonsoft.Json if (value == null) { WriteNull(); + return; } else if (value is IConvertible) {