Json deserializer collection perf improvements by avoiding boxing (dotnet/corefx...
authorSteve Harter <steveharter@users.noreply.github.com>
Mon, 15 Apr 2019 17:58:03 +0000 (10:58 -0700)
committerGitHub <noreply@github.com>
Mon, 15 Apr 2019 17:58:03 +0000 (10:58 -0700)
Commit migrated from https://github.com/dotnet/corefx/commit/6bfaf4116b5180c857bf6ad531f0655fd57c5eef

14 files changed:
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfo.cs
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfoCommon.cs
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfoNotNullable.cs
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfoNullable.cs
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleArray.cs
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleNull.cs
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleObject.cs
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.HandleEnumerable.cs
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReadStackFrame.cs
src/libraries/System.Text.Json/tests/Serialization/TestClasses.SimpleTestClass.cs [new file with mode: 0644]
src/libraries/System.Text.Json/tests/Serialization/TestClasses.SimpleTestClassWithNullables.cs [new file with mode: 0644]
src/libraries/System.Text.Json/tests/Serialization/TestClasses.SimpleTestClassWithObject.cs [new file with mode: 0644]
src/libraries/System.Text.Json/tests/Serialization/TestClasses.cs
src/libraries/System.Text.Json/tests/System.Text.Json.Tests.csproj

index a43d1d1..6f9b82f 100644 (file)
@@ -131,6 +131,7 @@ namespace System.Text.Json.Serialization
                     {
                         Type elementType = JsonClassInfo.GetElementType(RuntimePropertyType);
 
+                        // If the property type only has interface(s) exposed by JsonEnumerableT<T> then use JsonEnumerableT as the converter.
                         if (RuntimePropertyType.IsAssignableFrom(typeof(JsonEnumerableT<>).MakeGenericType(elementType)))
                         {
                             EnumerableConverter = s_jsonEnumerableConverter;
@@ -151,13 +152,15 @@ namespace System.Text.Json.Serialization
             return (TAttribute)PropertyInfo?.GetCustomAttribute(typeof(TAttribute), inherit: false);
         }
 
-        internal abstract void Read(JsonTokenType tokenType, JsonSerializerOptions options, ref ReadStack state, ref Utf8JsonReader reader);
+        internal abstract void ApplyNullValue(JsonSerializerOptions options, ref ReadStack state);
+            
+        internal abstract IList CreateConverterList();
 
+        internal abstract void Read(JsonTokenType tokenType, JsonSerializerOptions options, ref ReadStack state, ref Utf8JsonReader reader);
         internal abstract void ReadEnumerable(JsonTokenType tokenType, JsonSerializerOptions options, ref ReadStack state, ref Utf8JsonReader reader);
         internal abstract void SetValueAsObject(object obj, object value, JsonSerializerOptions options);
 
         internal abstract void Write(JsonSerializerOptions options, ref WriteStackFrame current, ref Utf8JsonWriter writer);
-
         internal abstract void WriteEnumerable(JsonSerializerOptions options, ref WriteStackFrame current, ref Utf8JsonWriter writer);
     }
 }
index 35efe45..b7365a8 100644 (file)
@@ -2,6 +2,8 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+using System.Collections;
+using System.Collections.Generic;
 using System.Diagnostics;
 using System.Reflection;
 using System.Text.Json.Serialization.Converters;
@@ -83,5 +85,10 @@ namespace System.Text.Json.Serialization
                 Set((TClass)obj, (TDeclaredProperty)value);
             }
         }
+
+        internal override IList CreateConverterList()
+        {
+            return new List<TDeclaredProperty>();
+        }
     }
 }
index c321937..a234ed4 100644 (file)
@@ -2,6 +2,7 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+using System.Collections.Generic;
 using System.Diagnostics;
 using System.Reflection;
 
@@ -62,18 +63,22 @@ namespace System.Text.Json.Serialization
             }
         }
 
+        // If this method is changed, also change JsonPropertyInfoNullable.ReadEnumerable and JsonSerializer.ApplyObjectToEnumerable
         internal override void ReadEnumerable(JsonTokenType tokenType, JsonSerializerOptions options, ref ReadStack state, ref Utf8JsonReader reader)
         {
-            if (ValueConverter != null)
+            if (ValueConverter == null || !ValueConverter.TryRead(RuntimePropertyType, ref reader, out TRuntimeProperty value))
             {
-                if (ValueConverter.TryRead(RuntimePropertyType, ref reader, out TRuntimeProperty value))
-                {
-                    ReadStackFrame.SetReturnValue(value, options, ref state.Current);
-                    return;
-                }
+                ThrowHelper.ThrowJsonReaderException_DeserializeUnableToConvertValue(RuntimePropertyType, reader, state);
+                return;
             }
 
-            ThrowHelper.ThrowJsonReaderException_DeserializeUnableToConvertValue(RuntimePropertyType, reader, state);
+            JsonSerializer.ApplyValueToEnumerable(ref value, options, ref state.Current);
+        }
+
+        internal override void ApplyNullValue(JsonSerializerOptions options, ref ReadStack state)
+        {
+            Debug.Assert(state.Current.JsonPropertyInfo != null);
+            state.Current.JsonPropertyInfo.SetValueAsObject(state.Current.ReturnValue, null, options);
         }
 
         // todo: have the caller check if current.Enumerator != null and call WriteEnumerable of the underlying property directly to avoid an extra virtual call.
@@ -127,7 +132,18 @@ namespace System.Text.Json.Serialization
             if (ValueConverter != null)
             {
                 Debug.Assert(current.Enumerator != null);
-                TRuntimeProperty value = (TRuntimeProperty)current.Enumerator.Current;
+
+                TRuntimeProperty value;
+                if (current.Enumerator is IEnumerator<TRuntimeProperty> enumerator)
+                {
+                    // Avoid boxing for strongly-typed enumerators such as returned from IList<T>.
+                    value = enumerator.Current;
+                }
+                else
+                {
+                    value = (TRuntimeProperty)current.Enumerator.Current;
+                }
+
                 if (value == null)
                 {
                     writer.WriteNullValue();
index d387d90..c159722 100644 (file)
@@ -2,6 +2,7 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+using System.Collections.Generic;
 using System.Diagnostics;
 using System.Reflection;
 
@@ -10,7 +11,7 @@ namespace System.Text.Json.Serialization
     /// <summary>
     /// Represents a strongly-typed property that is a <see cref="Nullable{T}"/>.
     /// </summary>
-    internal sealed class JsonPropertyInfoNullable<TClass, TProperty> 
+    internal sealed class JsonPropertyInfoNullable<TClass, TProperty>
         : JsonPropertyInfoCommon<TClass, TProperty?, TProperty>
         where TProperty : struct
     {
@@ -61,16 +62,21 @@ namespace System.Text.Json.Serialization
 
         internal override void ReadEnumerable(JsonTokenType tokenType, JsonSerializerOptions options, ref ReadStack state, ref Utf8JsonReader reader)
         {
-            if (ValueConverter != null)
+            if (ValueConverter == null || !ValueConverter.TryRead(typeof(TProperty), ref reader, out TProperty value))
             {
-                if (ValueConverter.TryRead(s_underlyingType, ref reader, out TProperty value))
-                {
-                    ReadStackFrame.SetReturnValue(value, options, ref state.Current);
-                    return;
-                }
+                ThrowHelper.ThrowJsonReaderException_DeserializeUnableToConvertValue(RuntimePropertyType, reader, state);
+                return;
             }
 
-            ThrowHelper.ThrowJsonReaderException_DeserializeUnableToConvertValue(RuntimePropertyType, reader, state);
+            // Converting to TProperty? here lets us share a common ApplyValue() with ApplyNullValue().
+            TProperty? nullableValue = new TProperty?(value);
+            JsonSerializer.ApplyValueToEnumerable(ref nullableValue, options, ref state.Current);
+        }
+
+        internal override void ApplyNullValue(JsonSerializerOptions options, ref ReadStack state)
+        {
+            TProperty? nullableValue = null;
+            JsonSerializer.ApplyValueToEnumerable(ref nullableValue, options, ref state.Current);
         }
 
         // todo: have the caller check if current.Enumerator != null and call WriteEnumerable of the underlying property directly to avoid an extra virtual call.
@@ -124,7 +130,18 @@ namespace System.Text.Json.Serialization
             if (ValueConverter != null)
             {
                 Debug.Assert(current.Enumerator != null);
-                TProperty? value = (TProperty?)current.Enumerator.Current;
+
+                TProperty? value;
+                if (current.Enumerator is IEnumerator<TProperty?> enumerator)
+                {
+                    // Avoid boxing for strongly-typed enumerators such as returned from IList<T>.
+                    value = enumerator.Current;
+                }
+                else
+                {
+                    value = (TProperty?)current.Enumerator.Current;
+                }
+
                 if (value == null)
                 {
                     writer.WriteNullValue();
index 4f4c30c..ebd9fef 100644 (file)
@@ -3,6 +3,7 @@
 // See the LICENSE file in the project root for more information.
 
 using System.Collections;
+using System.Collections.Generic;
 using System.Diagnostics;
 using System.Text.Json.Serialization.Policies;
 
@@ -137,7 +138,7 @@ namespace System.Text.Json.Serialization
                 // else there must be an outer object, so we'll return false here.
             }
 
-            ReadStackFrame.SetReturnValue(value, options, ref state.Current, setPropertyDirectly: setPropertyDirectly);
+            ApplyObjectToEnumerable(value, options, ref state.Current, setPropertyDirectly: setPropertyDirectly);
 
             if (!valueReturning)
             {
@@ -146,5 +147,73 @@ namespace System.Text.Json.Serialization
 
             return false;
         }
+
+        // If this method is changed, also change ApplyValueToEnumerable.
+        internal static void ApplyObjectToEnumerable(object value, JsonSerializerOptions options, ref ReadStackFrame frame, bool setPropertyDirectly = false)
+        {
+            if (frame.IsEnumerable())
+            {
+                if (frame.TempEnumerableValues != null)
+                {
+                    frame.TempEnumerableValues.Add(value);
+                }
+                else
+                {
+                    ((IList)frame.ReturnValue).Add(value);
+                }
+            }
+            else if (!setPropertyDirectly && frame.IsPropertyEnumerable())
+            {
+                Debug.Assert(frame.JsonPropertyInfo != null);
+                Debug.Assert(frame.ReturnValue != null);
+                if (frame.TempEnumerableValues != null)
+                {
+                    frame.TempEnumerableValues.Add(value);
+                }
+                else
+                {
+                    ((IList)frame.JsonPropertyInfo.GetValueAsObject(frame.ReturnValue, options)).Add(value);
+                }
+            }
+            else
+            {
+                Debug.Assert(frame.JsonPropertyInfo != null);
+                frame.JsonPropertyInfo.SetValueAsObject(frame.ReturnValue, value, options);
+            }
+        }
+
+        // If this method is changed, also change ApplyObjectToEnumerable.
+        internal static void ApplyValueToEnumerable<TProperty>(ref TProperty value, JsonSerializerOptions options, ref ReadStackFrame frame)
+        {
+            if (frame.IsEnumerable())
+            {
+                if (frame.TempEnumerableValues != null)
+                {
+                    ((IList<TProperty>)frame.TempEnumerableValues).Add(value);
+                }
+                else
+                {
+                    ((IList<TProperty>)frame.ReturnValue).Add(value);
+                }
+            }
+            else if (frame.IsPropertyEnumerable())
+            {
+                Debug.Assert(frame.JsonPropertyInfo != null);
+                Debug.Assert(frame.ReturnValue != null);
+                if (frame.TempEnumerableValues != null)
+                {
+                    ((IList<TProperty>)frame.TempEnumerableValues).Add(value);
+                }
+                else
+                {
+                    ((IList<TProperty>)frame.JsonPropertyInfo.GetValueAsObject(frame.ReturnValue, options)).Add(value);
+                }
+            }
+            else
+            {
+                Debug.Assert(frame.JsonPropertyInfo != null);
+                frame.JsonPropertyInfo.SetValueAsObject(frame.ReturnValue, value, options);
+            }
+        }
     }
 }
index ace0c71..6f1d136 100644 (file)
@@ -2,6 +2,7 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+using System.Collections;
 using System.Diagnostics;
 
 namespace System.Text.Json.Serialization
@@ -29,9 +30,15 @@ namespace System.Text.Json.Serialization
                 ThrowHelper.ThrowJsonReaderException_DeserializeCannotBeNull(reader, state);
             }
 
-            if (state.Current.IsEnumerable() || state.Current.IsPropertyEnumerable())
+            if (state.Current.IsEnumerable())
             {
-                ReadStackFrame.SetReturnValue(null, options, ref state.Current);
+                ApplyObjectToEnumerable(null, options, ref state.Current);
+                return false;
+            }
+
+            if (state.Current.IsPropertyEnumerable())
+            {
+                state.Current.JsonPropertyInfo.ApplyNullValue(options, ref state);
                 return false;
             }
 
index afaf9c4..c5dd88d 100644 (file)
@@ -2,6 +2,8 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+using System.Collections;
+
 namespace System.Text.Json.Serialization
 {
     public static partial class JsonSerializer
@@ -55,7 +57,7 @@ namespace System.Text.Json.Serialization
             }
 
             state.Pop();
-            ReadStackFrame.SetReturnValue(value, options, ref state.Current);
+            ApplyObjectToEnumerable(value, options, ref state.Current);
             return false;
         }
     }
index ea02e71..6681727 100644 (file)
@@ -34,6 +34,17 @@ namespace System.Text.Json.Serialization
 
             if (state.Current.Enumerator == null)
             {
+                IEnumerable enumerable = (IEnumerable)jsonPropertyInfo.GetValueAsObject(state.Current.CurrentValue, options);
+
+                if (enumerable == null)
+                {
+                    // Write a null object or enumerable.
+                    writer.WriteNull(jsonPropertyInfo._name);
+                    return true;
+                }
+
+                state.Current.Enumerator = enumerable.GetEnumerator();
+
                 if (jsonPropertyInfo._name == null)
                 {
                     writer.WriteStartArray();
@@ -42,16 +53,9 @@ namespace System.Text.Json.Serialization
                 {
                     writer.WriteStartArray(jsonPropertyInfo._name);
                 }
-
-                IEnumerable enumerable = (IEnumerable)jsonPropertyInfo.GetValueAsObject(state.Current.CurrentValue, options);
-
-                if (enumerable != null)
-                {
-                    state.Current.Enumerator = enumerable.GetEnumerator();
-                }
             }
 
-            if (state.Current.Enumerator != null && state.Current.Enumerator.MoveNext())
+            if (state.Current.Enumerator.MoveNext())
             {
                 // Check for polymorphism.
                 if (elementClassInfo.ClassType == ClassType.Unknown)
index be230e9..ee8cce3 100644 (file)
@@ -20,7 +20,7 @@ namespace System.Text.Json.Serialization
         internal bool EnumerableCreated;
 
         // Support System.Array and other types that don't implement IList
-        internal List<object> TempEnumerableValues;
+        internal IList TempEnumerableValues;
 
         // For performance, we order the properties by the first deserialize and PropertyIndex helps find the right slot quicker.
         internal int PropertyIndex;
@@ -93,10 +93,23 @@ namespace System.Text.Json.Serialization
 
         internal static object CreateEnumerableValue(ref Utf8JsonReader reader, ref ReadStack state, JsonSerializerOptions options)
         {
+            JsonPropertyInfo jsonPropertyInfo = state.Current.JsonPropertyInfo;
+
             // If the property has an EnumerableConverter, then we use tempEnumerableValues.
-            if (state.Current.JsonPropertyInfo.EnumerableConverter != null)
+            if (jsonPropertyInfo.EnumerableConverter != null)
             {
-                state.Current.TempEnumerableValues = new List<object>();
+                IList converterList;
+                if (jsonPropertyInfo.ElementClassInfo.ClassType == ClassType.Value)
+                {
+                    converterList = jsonPropertyInfo.ElementClassInfo.GetPolicyProperty().CreateConverterList();
+                }
+                else
+                {
+                    converterList =  new List<object>();
+                }
+
+                state.Current.TempEnumerableValues = converterList;
+
                 return null;
             }
 
@@ -134,38 +147,5 @@ namespace System.Text.Json.Serialization
             Debug.Assert(ReturnValue == null);
             ReturnValue = value;
         }
-
-        internal static void SetReturnValue(object value, JsonSerializerOptions options, ref ReadStackFrame current, bool setPropertyDirectly = false)
-        {
-            if (current.IsEnumerable())
-            {
-                if (current.TempEnumerableValues != null)
-                {
-                    current.TempEnumerableValues.Add(value);
-                }
-                else
-                {
-                    ((IList)current.ReturnValue).Add(value);
-                }
-            }
-            else if (!setPropertyDirectly && current.IsPropertyEnumerable())
-            {
-                Debug.Assert(current.JsonPropertyInfo != null);
-                Debug.Assert(current.ReturnValue != null);
-                if (current.TempEnumerableValues != null)
-                {
-                    current.TempEnumerableValues.Add(value);
-                }
-                else
-                {
-                    ((IList)current.JsonPropertyInfo.GetValueAsObject(current.ReturnValue, options)).Add(value);
-                }
-            }
-            else
-            {
-                Debug.Assert(current.JsonPropertyInfo != null);
-                current.JsonPropertyInfo.SetValueAsObject(current.ReturnValue, value, options);
-            }
-        }
     }
 }
diff --git a/src/libraries/System.Text.Json/tests/Serialization/TestClasses.SimpleTestClass.cs b/src/libraries/System.Text.Json/tests/Serialization/TestClasses.SimpleTestClass.cs
new file mode 100644 (file)
index 0000000..ba35451
--- /dev/null
@@ -0,0 +1,203 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Linq;
+using Xunit;
+
+namespace System.Text.Json.Serialization.Tests
+{
+    public class SimpleTestClass : ITestClass
+    {
+        public short MyInt16 { get; set; }
+        public int MyInt32 { get; set; }
+        public long MyInt64 { get; set; }
+        public ushort MyUInt16 { get; set; }
+        public uint MyUInt32 { get; set; }
+        public ulong MyUInt64 { get; set; }
+        public byte MyByte { get; set; }
+        public sbyte MySByte { get; set; }
+        public char MyChar { get; set; }
+        public string MyString { get; set; }
+        public decimal MyDecimal { get; set; }
+        public bool MyBooleanTrue { get; set; }
+        public bool MyBooleanFalse { get; set; }
+        public float MySingle { get; set; }
+        public double MyDouble { get; set; }
+        public DateTime MyDateTime { get; set; }
+        public DateTimeOffset MyDateTimeOffset { get; set; }
+        public SampleEnum MyEnum { get; set; }
+        public short[] MyInt16Array { get; set; }
+        public int[] MyInt32Array { get; set; }
+        public long[] MyInt64Array { get; set; }
+        public ushort[] MyUInt16Array { get; set; }
+        public uint[] MyUInt32Array { get; set; }
+        public ulong[] MyUInt64Array { get; set; }
+        public byte[] MyByteArray { get; set; }
+        public sbyte[] MySByteArray { get; set; }
+        public char[] MyCharArray { get; set; }
+        public string[] MyStringArray { get; set; }
+        public decimal[] MyDecimalArray { get; set; }
+        public bool[] MyBooleanTrueArray { get; set; }
+        public bool[] MyBooleanFalseArray { get; set; }
+        public float[] MySingleArray { get; set; }
+        public double[] MyDoubleArray { get; set; }
+        public DateTime[] MyDateTimeArray { get; set; }
+        public DateTimeOffset[] MyDateTimeOffsetArray { get; set; }
+        public SampleEnum[] MyEnumArray { get; set; }
+        public List<string> MyStringList { get; set; }
+        public IEnumerable<string> MyStringIEnumerableT { get; set; }
+        public IList<string> MyStringIListT { get; set; }
+        public ICollection<string> MyStringICollectionT { get; set; }
+        public IReadOnlyCollection<string> MyStringIReadOnlyCollectionT { get; set; }
+        public IReadOnlyList<string> MyStringIReadOnlyListT { get; set; }
+
+        public static readonly string s_json = $"{{{s_partialJsonProperties},{s_partialJsonArrays}}}";
+        public static readonly string s_json_flipped = $"{{{s_partialJsonArrays},{s_partialJsonProperties}}}";
+
+        private const string s_partialJsonProperties =
+                @"""MyInt16"" : 1," +
+                @"""MyInt32"" : 2," +
+                @"""MyInt64"" : 3," +
+                @"""MyUInt16"" : 4," +
+                @"""MyUInt32"" : 5," +
+                @"""MyUInt64"" : 6," +
+                @"""MyByte"" : 7," +
+                @"""MySByte"" : 8," +
+                @"""MyChar"" : ""a""," +
+                @"""MyString"" : ""Hello""," +
+                @"""MyBooleanTrue"" : true," +
+                @"""MyBooleanFalse"" : false," +
+                @"""MySingle"" : 1.1," +
+                @"""MyDouble"" : 2.2," +
+                @"""MyDecimal"" : 3.3," +
+                @"""MyDateTime"" : ""2019-01-30T12:01:02.0000000Z""," +
+                @"""MyDateTimeOffset"" : ""2019-01-30T12:01:02.0000000+01:00""," +
+                @"""MyEnum"" : 2"; // int by default
+
+        private const string s_partialJsonArrays =
+                @"""MyInt16Array"" : [1]," +
+                @"""MyInt32Array"" : [2]," +
+                @"""MyInt64Array"" : [3]," +
+                @"""MyUInt16Array"" : [4]," +
+                @"""MyUInt32Array"" : [5]," +
+                @"""MyUInt64Array"" : [6]," +
+                @"""MyByteArray"" : [7]," +
+                @"""MySByteArray"" : [8]," +
+                @"""MyCharArray"" : [""a""]," +
+                @"""MyStringArray"" : [""Hello""]," +
+                @"""MyBooleanTrueArray"" : [true]," +
+                @"""MyBooleanFalseArray"" : [false]," +
+                @"""MySingleArray"" : [1.1]," +
+                @"""MyDoubleArray"" : [2.2]," +
+                @"""MyDecimalArray"" : [3.3]," +
+                @"""MyDateTimeArray"" : [""2019-01-30T12:01:02.0000000Z""]," +
+                @"""MyDateTimeOffsetArray"" : [""2019-01-30T12:01:02.0000000+01:00""]," +
+                @"""MyEnumArray"" : [2]," + // int by default
+                @"""MyStringList"" : [""Hello""]," +
+                @"""MyStringIEnumerableT"" : [""Hello""]," +
+                @"""MyStringIListT"" : [""Hello""]," +
+                @"""MyStringICollectionT"" : [""Hello""]," +
+                @"""MyStringIReadOnlyCollectionT"" : [""Hello""]," +
+                @"""MyStringIReadOnlyListT"" : [""Hello""]";
+
+        public static readonly byte[] s_data = Encoding.UTF8.GetBytes(s_json);
+
+        public void Initialize()
+        {
+            MyInt16 = 1;
+            MyInt32 = 2;
+            MyInt64 = 3;
+            MyUInt16 = 4;
+            MyUInt32 = 5;
+            MyUInt64 = 6;
+            MyByte = 7;
+            MySByte = 8;
+            MyChar = 'a';
+            MyString = "Hello";
+            MyBooleanTrue = true;
+            MyBooleanFalse = false;
+            MySingle = 1.1f;
+            MyDouble = 2.2d;
+            MyDecimal = 3.3m;
+            MyDateTime = new DateTime(2019, 1, 30, 12, 1, 2, DateTimeKind.Utc);
+            MyDateTimeOffset = new DateTimeOffset(2019, 1, 30, 12, 1, 2, new TimeSpan(1, 0, 0));
+            MyEnum = SampleEnum.Two;
+
+            MyInt16Array = new short[] { 1 };
+            MyInt32Array = new int[] { 2 };
+            MyInt64Array = new long[] { 3 };
+            MyUInt16Array = new ushort[] { 4 };
+            MyUInt32Array = new uint[] { 5 };
+            MyUInt64Array = new ulong[] { 6 };
+            MyByteArray = new byte[] { 7 };
+            MySByteArray = new sbyte[] { 8 };
+            MyCharArray = new char[] { 'a' };
+            MyStringArray = new string[] { "Hello" };
+            MyBooleanTrueArray = new bool[] { true };
+            MyBooleanFalseArray = new bool[] { false };
+            MySingleArray = new float[] { 1.1f };
+            MyDoubleArray = new double[] { 2.2d };
+            MyDecimalArray = new decimal[] { 3.3m };
+            MyDateTimeArray = new DateTime[] { new DateTime(2019, 1, 30, 12, 1, 2, DateTimeKind.Utc) };
+            MyDateTimeOffsetArray = new DateTimeOffset[] { new DateTimeOffset(2019, 1, 30, 12, 1, 2, new TimeSpan(1, 0, 0)) };
+            MyEnumArray = new SampleEnum[] { SampleEnum.Two };
+
+            MyStringList = new List<string>() { "Hello" };
+            MyStringIEnumerableT = new string[] { "Hello" };
+            MyStringIListT = new string[] { "Hello" };
+            MyStringICollectionT = new string[] { "Hello" };
+            MyStringIReadOnlyCollectionT = new string[] { "Hello" };
+            MyStringIReadOnlyListT = new string[] { "Hello" };
+        }
+
+        public void Verify()
+        {
+            Assert.Equal((short)1, MyInt16);
+            Assert.Equal((int)2, MyInt32);
+            Assert.Equal((long)3, MyInt64);
+            Assert.Equal((ushort)4, MyUInt16);
+            Assert.Equal((uint)5, MyUInt32);
+            Assert.Equal((ulong)6, MyUInt64);
+            Assert.Equal((byte)7, MyByte);
+            Assert.Equal((sbyte)8, MySByte);
+            Assert.Equal('a', MyChar);
+            Assert.Equal("Hello", MyString);
+            Assert.Equal(3.3m, MyDecimal);
+            Assert.Equal(false, MyBooleanFalse);
+            Assert.Equal(true, MyBooleanTrue);
+            Assert.Equal(1.1f, MySingle);
+            Assert.Equal(2.2d, MyDouble);
+            Assert.Equal(new DateTime(2019, 1, 30, 12, 1, 2, DateTimeKind.Utc), MyDateTime);
+            Assert.Equal(new DateTimeOffset(2019, 1, 30, 12, 1, 2, new TimeSpan(1, 0, 0)), MyDateTimeOffset);
+            Assert.Equal(SampleEnum.Two, MyEnum);
+
+            Assert.Equal((short)1, MyInt16Array[0]);
+            Assert.Equal((int)2, MyInt32Array[0]);
+            Assert.Equal((long)3, MyInt64Array[0]);
+            Assert.Equal((ushort)4, MyUInt16Array[0]);
+            Assert.Equal((uint)5, MyUInt32Array[0]);
+            Assert.Equal((ulong)6, MyUInt64Array[0]);
+            Assert.Equal((byte)7, MyByteArray[0]);
+            Assert.Equal((sbyte)8, MySByteArray[0]);
+            Assert.Equal('a', MyCharArray[0]);
+            Assert.Equal("Hello", MyStringArray[0]);
+            Assert.Equal(3.3m, MyDecimalArray[0]);
+            Assert.Equal(false, MyBooleanFalseArray[0]);
+            Assert.Equal(true, MyBooleanTrueArray[0]);
+            Assert.Equal(1.1f, MySingleArray[0]);
+            Assert.Equal(2.2d, MyDoubleArray[0]);
+            Assert.Equal(new DateTime(2019, 1, 30, 12, 1, 2, DateTimeKind.Utc), MyDateTimeArray[0]);
+            Assert.Equal(new DateTimeOffset(2019, 1, 30, 12, 1, 2, new TimeSpan(1, 0, 0)), MyDateTimeOffsetArray[0]);
+            Assert.Equal(SampleEnum.Two, MyEnumArray[0]);
+
+            Assert.Equal("Hello", MyStringList[0]);
+            Assert.Equal("Hello", MyStringIEnumerableT.First());
+            Assert.Equal("Hello", MyStringIListT[0]);
+            Assert.Equal("Hello", MyStringICollectionT.First());
+            Assert.Equal("Hello", MyStringIReadOnlyCollectionT.First());
+            Assert.Equal("Hello", MyStringIReadOnlyListT[0]);
+        }
+    }
+}
diff --git a/src/libraries/System.Text.Json/tests/Serialization/TestClasses.SimpleTestClassWithNullables.cs b/src/libraries/System.Text.Json/tests/Serialization/TestClasses.SimpleTestClassWithNullables.cs
new file mode 100644 (file)
index 0000000..ac6953d
--- /dev/null
@@ -0,0 +1,252 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+
+namespace System.Text.Json.Serialization.Tests
+{
+    public abstract class SimpleBaseClassWithNullables
+    {
+        public short? MyInt16 { get; set; }
+        public int? MyInt32 { get; set; }
+        public long? MyInt64 { get; set; }
+        public ushort? MyUInt16 { get; set; }
+        public uint? MyUInt32 { get; set; }
+        public ulong? MyUInt64 { get; set; }
+        public byte? MyByte { get; set; }
+        public sbyte? MySByte { get; set; }
+        public char? MyChar { get; set; }
+        public decimal? MyDecimal { get; set; }
+        public bool? MyBooleanTrue { get; set; }
+        public bool? MyBooleanFalse { get; set; }
+        public float? MySingle { get; set; }
+        public double? MyDouble { get; set; }
+        public DateTime? MyDateTime { get; set; }
+        public DateTimeOffset? MyDateTimeOffset { get; set; }
+        public SampleEnum? MyEnum { get; set; }
+        public short?[] MyInt16Array { get; set; }
+        public int?[] MyInt32Array { get; set; }
+        public long?[] MyInt64Array { get; set; }
+        public ushort?[] MyUInt16Array { get; set; }
+        public uint?[] MyUInt32Array { get; set; }
+        public ulong?[] MyUInt64Array { get; set; }
+        public byte?[] MyByteArray { get; set; }
+        public sbyte?[] MySByteArray { get; set; }
+        public char?[] MyCharArray { get; set; }
+        public decimal?[] MyDecimalArray { get; set; }
+        public bool?[] MyBooleanTrueArray { get; set; }
+        public bool?[] MyBooleanFalseArray { get; set; }
+        public float?[] MySingleArray { get; set; }
+        public double?[] MyDoubleArray { get; set; }
+        public DateTime?[] MyDateTimeArray { get; set; }
+        public DateTimeOffset?[] MyDateTimeOffsetArray { get; set; }
+        public SampleEnum?[] MyEnumArray { get; set; }
+    }
+
+    public class SimpleTestClassWithNulls : SimpleBaseClassWithNullables, ITestClass
+    {
+        public void Initialize()
+        {
+        }
+
+        public void Verify()
+        {
+            Assert.Null(MyInt16);
+            Assert.Null(MyInt32);
+            Assert.Null(MyInt64);
+            Assert.Null(MyUInt16);
+            Assert.Null(MyUInt32);
+            Assert.Null(MyUInt64);
+            Assert.Null(MyByte);
+            Assert.Null(MySByte);
+            Assert.Null(MyChar);
+            Assert.Null(MyDecimal);
+            Assert.Null(MyBooleanFalse);
+            Assert.Null(MyBooleanTrue);
+            Assert.Null(MySingle);
+            Assert.Null(MyDouble);
+            Assert.Null(MyDateTime);
+            Assert.Null(MyDateTimeOffset);
+            Assert.Null(MyEnum);
+
+            Assert.Null(MyInt16Array);
+            Assert.Null(MyInt32Array);
+            Assert.Null(MyInt64Array);
+            Assert.Null(MyUInt16Array);
+            Assert.Null(MyUInt32Array);
+            Assert.Null(MyUInt64Array);
+            Assert.Null(MyByteArray);
+            Assert.Null(MySByteArray);
+            Assert.Null(MyCharArray);
+            Assert.Null(MyDecimalArray);
+            Assert.Null(MyBooleanFalseArray);
+            Assert.Null(MyBooleanTrueArray);
+            Assert.Null(MySingleArray);
+            Assert.Null(MyDoubleArray);
+            Assert.Null(MyDateTimeArray);
+            Assert.Null(MyDateTimeOffsetArray);
+            Assert.Null(MyEnumArray);
+        }
+        public static readonly string s_json =
+                @"{" +
+                @"""MyInt16"" : null," +
+                @"""MyInt32"" : null," +
+                @"""MyInt64"" : null," +
+                @"""MyUInt16"" : null," +
+                @"""MyUInt32"" : null," +
+                @"""MyUInt64"" : null," +
+                @"""MyByte"" : null," +
+                @"""MySByte"" : null," +
+                @"""MyChar"" : null," +
+                @"""MyBooleanTrue"" : null," +
+                @"""MyBooleanFalse"" : null," +
+                @"""MySingle"" : null," +
+                @"""MyDouble"" : null," +
+                @"""MyDecimal"" : null," +
+                @"""MyDateTime"" : null," +
+                @"""MyDateTimeOffset"" : null," +
+                @"""MyEnum"" : null," +
+                @"""MyInt16Array"" : null," +
+                @"""MyInt32Array"" : null," +
+                @"""MyInt64Array"" : null," +
+                @"""MyUInt16Array"" : null," +
+                @"""MyUInt32Array"" : null," +
+                @"""MyUInt64Array"" : null," +
+                @"""MyByteArray"" : null," +
+                @"""MySByteArray"" : null," +
+                @"""MyCharArray"" : null," +
+                @"""MyBooleanTrueArray"" : null," +
+                @"""MyBooleanFalseArray"" : null," +
+                @"""MySingleArray"" : null," +
+                @"""MyDoubleArray"" : null," +
+                @"""MyDecimalArray"" : null," +
+                @"""MyDateTimeArray"" : null," +
+                @"""MyDateTimeOffsetArray"" : null," +
+                @"""MyEnumArray"" : null" +
+                @"}";
+
+        public static readonly byte[] s_data = Encoding.UTF8.GetBytes(s_json);
+    }
+
+    public class SimpleTestClassWithNullables : SimpleBaseClassWithNullables, ITestClass
+    {
+        public static readonly string s_json =
+                @"{" +
+                @"""MyInt16"" : 1," +
+                @"""MyInt32"" : 2," +
+                @"""MyInt64"" : 3," +
+                @"""MyUInt16"" : 4," +
+                @"""MyUInt32"" : 5," +
+                @"""MyUInt64"" : 6," +
+                @"""MyByte"" : 7," +
+                @"""MySByte"" : 8," +
+                @"""MyChar"" : ""a""," +
+                @"""MyBooleanTrue"" : true," +
+                @"""MyBooleanFalse"" : false," +
+                @"""MySingle"" : 1.1," +
+                @"""MyDouble"" : 2.2," +
+                @"""MyDecimal"" : 3.3," +
+                @"""MyDateTime"" : ""2019-01-30T12:01:02.0000000Z""," +
+                @"""MyDateTimeOffset"" : ""2019-01-30T12:01:02.0000000+01:00""," +
+                @"""MyEnum"" : 2," +
+                @"""MyInt16Array"" : [1]," +
+                @"""MyInt32Array"" : [2]," +
+                @"""MyInt64Array"" : [3]," +
+                @"""MyUInt16Array"" : [4]," +
+                @"""MyUInt32Array"" : [5]," +
+                @"""MyUInt64Array"" : [6]," +
+                @"""MyByteArray"" : [7]," +
+                @"""MySByteArray"" : [8]," +
+                @"""MyCharArray"" : [""a""]," +
+                @"""MyBooleanTrueArray"" : [true]," +
+                @"""MyBooleanFalseArray"" : [false]," +
+                @"""MySingleArray"" : [1.1]," +
+                @"""MyDoubleArray"" : [2.2]," +
+                @"""MyDecimalArray"" : [3.3]," +
+                @"""MyDateTimeArray"" : [""2019-01-30T12:01:02.0000000Z""]," +
+                @"""MyDateTimeOffsetArray"" : [""2019-01-30T12:01:02.0000000+01:00""]," +
+                @"""MyEnumArray"" : [2]" +
+                @"}";
+
+        public static readonly byte[] s_data = Encoding.UTF8.GetBytes(s_json);
+
+        public void Initialize()
+        {
+            MyInt16 = 1;
+            MyInt32 = 2;
+            MyInt64 = 3;
+            MyUInt16 = 4;
+            MyUInt32 = 5;
+            MyUInt64 = 6;
+            MyByte = 7;
+            MySByte = 8;
+            MyChar = 'a';
+            MyBooleanTrue = true;
+            MyBooleanFalse = false;
+            MySingle = 1.1f;
+            MyDouble = 2.2d;
+            MyDecimal = 3.3m;
+            MyDateTime = new DateTime(2019, 1, 30, 12, 1, 2, DateTimeKind.Utc);
+            MyDateTimeOffset = new DateTimeOffset(2019, 1, 30, 12, 1, 2, new TimeSpan(1, 0, 0));
+            MyEnum = SampleEnum.Two;
+
+            MyInt16Array = new short?[] { 1 };
+            MyInt32Array = new int?[] { 2 };
+            MyInt64Array = new long?[] { 3 };
+            MyUInt16Array = new ushort?[] { 4 };
+            MyUInt32Array = new uint?[] { 5 };
+            MyUInt64Array = new ulong?[] { 6 };
+            MyByteArray = new byte?[] { 7 };
+            MySByteArray = new sbyte?[] { 8 };
+            MyCharArray = new char?[] { 'a' };
+            MyBooleanTrueArray = new bool?[] { true };
+            MyBooleanFalseArray = new bool?[] { false };
+            MySingleArray = new float?[] { 1.1f };
+            MyDoubleArray = new double?[] { 2.2d };
+            MyDecimalArray = new decimal?[] { 3.3m };
+            MyDateTimeArray = new DateTime?[] { new DateTime(2019, 1, 30, 12, 1, 2, DateTimeKind.Utc) };
+            MyDateTimeOffsetArray = new DateTimeOffset?[] { new DateTimeOffset(2019, 1, 30, 12, 1, 2, new TimeSpan(1, 0, 0)) };
+            MyEnumArray = new SampleEnum?[] { SampleEnum.Two };
+        }
+
+        public void Verify()
+        {
+            Assert.Equal(MyInt16, (short)1);
+            Assert.Equal(MyInt32, (int)2);
+            Assert.Equal(MyInt64, (long)3);
+            Assert.Equal(MyUInt16, (ushort)4);
+            Assert.Equal(MyUInt32, (uint)5);
+            Assert.Equal(MyUInt64, (ulong)6);
+            Assert.Equal(MyByte, (byte)7);
+            Assert.Equal(MySByte, (sbyte)8);
+            Assert.Equal(MyChar, 'a');
+            Assert.Equal(MyDecimal, 3.3m);
+            Assert.Equal(MyBooleanFalse, false);
+            Assert.Equal(MyBooleanTrue, true);
+            Assert.Equal(MySingle, 1.1f);
+            Assert.Equal(MyDouble, 2.2d);
+            Assert.Equal(MyDateTime, new DateTime(2019, 1, 30, 12, 1, 2, DateTimeKind.Utc));
+            Assert.Equal(MyDateTimeOffset, new DateTimeOffset(2019, 1, 30, 12, 1, 2, new TimeSpan(1, 0, 0)));
+            Assert.Equal(MyEnum, SampleEnum.Two);
+
+            Assert.Equal((short)1, MyInt16Array[0]);
+            Assert.Equal((int)2, MyInt32Array[0]);
+            Assert.Equal((long)3, MyInt64Array[0]);
+            Assert.Equal((ushort)4, MyUInt16Array[0]);
+            Assert.Equal((uint)5, MyUInt32Array[0]);
+            Assert.Equal((ulong)6, MyUInt64Array[0]);
+            Assert.Equal((byte)7, MyByteArray[0]);
+            Assert.Equal((sbyte)8, MySByteArray[0]);
+            Assert.Equal('a', MyCharArray[0]);
+            Assert.Equal(3.3m, MyDecimalArray[0]);
+            Assert.Equal(false, MyBooleanFalseArray[0]);
+            Assert.Equal(true, MyBooleanTrueArray[0]);
+            Assert.Equal(1.1f, MySingleArray[0]);
+            Assert.Equal(2.2d, MyDoubleArray[0]);
+            Assert.Equal(new DateTime(2019, 1, 30, 12, 1, 2, DateTimeKind.Utc), MyDateTimeArray[0]);
+            Assert.Equal(new DateTimeOffset(2019, 1, 30, 12, 1, 2, new TimeSpan(1, 0, 0)), MyDateTimeOffsetArray[0]);
+            Assert.Equal(SampleEnum.Two, MyEnumArray[0]);
+        }
+    }
+}
diff --git a/src/libraries/System.Text.Json/tests/Serialization/TestClasses.SimpleTestClassWithObject.cs b/src/libraries/System.Text.Json/tests/Serialization/TestClasses.SimpleTestClassWithObject.cs
new file mode 100644 (file)
index 0000000..f726593
--- /dev/null
@@ -0,0 +1,192 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Linq;
+using Xunit;
+
+namespace System.Text.Json.Serialization.Tests
+{
+    public class SimpleTestClassWithObject : ITestClass
+    {
+        public object MyInt16 { get; set; }
+        public object MyInt32 { get; set; }
+        public object MyInt64 { get; set; }
+        public object MyUInt16 { get; set; }
+        public object MyUInt32 { get; set; }
+        public object MyUInt64 { get; set; }
+        public object MyByte { get; set; }
+        public object MySByte { get; set; }
+        public object MyChar { get; set; }
+        public object MyString { get; set; }
+        public object MyDecimal { get; set; }
+        public object MyBooleanTrue { get; set; }
+        public object MyBooleanFalse { get; set; }
+        public object MySingle { get; set; }
+        public object MyDouble { get; set; }
+        public object MyDateTime { get; set; }
+        public object MyEnum { get; set; }
+        public object MyInt16Array { get; set; }
+        public object MyInt32Array { get; set; }
+        public object MyInt64Array { get; set; }
+        public object MyUInt16Array { get; set; }
+        public object MyUInt32Array { get; set; }
+        public object MyUInt64Array { get; set; }
+        public object MyByteArray { get; set; }
+        public object MySByteArray { get; set; }
+        public object MyCharArray { get; set; }
+        public object MyStringArray { get; set; }
+        public object MyDecimalArray { get; set; }
+        public object MyBooleanTrueArray { get; set; }
+        public object MyBooleanFalseArray { get; set; }
+        public object MySingleArray { get; set; }
+        public object MyDoubleArray { get; set; }
+        public object MyDateTimeArray { get; set; }
+        public object MyEnumArray { get; set; }
+        public object MyStringList { get; set; }
+        public object MyStringIEnumerableT { get; set; }
+        public object MyStringIListT { get; set; }
+        public object MyStringICollectionT { get; set; }
+        public object MyStringIReadOnlyCollectionT { get; set; }
+        public object MyStringIReadOnlyListT { get; set; }
+
+        public static readonly string s_json =
+                @"{" +
+                @"""MyInt16"" : 1," +
+                @"""MyInt32"" : 2," +
+                @"""MyInt64"" : 3," +
+                @"""MyUInt16"" : 4," +
+                @"""MyUInt32"" : 5," +
+                @"""MyUInt64"" : 6," +
+                @"""MyByte"" : 7," +
+                @"""MySByte"" : 8," +
+                @"""MyChar"" : ""a""," +
+                @"""MyString"" : ""Hello""," +
+                @"""MyBooleanTrue"" : true," +
+                @"""MyBooleanFalse"" : false," +
+                @"""MySingle"" : 1.1," +
+                @"""MyDouble"" : 2.2," +
+                @"""MyDecimal"" : 3.3," +
+                @"""MyDateTime"" : ""2019-01-30T12:01:02.0000000Z""," +
+                @"""MyEnum"" : 2," + // int by default
+                @"""MyInt16Array"" : [1]," +
+                @"""MyInt32Array"" : [2]," +
+                @"""MyInt64Array"" : [3]," +
+                @"""MyUInt16Array"" : [4]," +
+                @"""MyUInt32Array"" : [5]," +
+                @"""MyUInt64Array"" : [6]," +
+                @"""MyByteArray"" : [7]," +
+                @"""MySByteArray"" : [8]," +
+                @"""MyCharArray"" : [""a""]," +
+                @"""MyStringArray"" : [""Hello""]," +
+                @"""MyBooleanTrueArray"" : [true]," +
+                @"""MyBooleanFalseArray"" : [false]," +
+                @"""MySingleArray"" : [1.1]," +
+                @"""MyDoubleArray"" : [2.2]," +
+                @"""MyDecimalArray"" : [3.3]," +
+                @"""MyDateTimeArray"" : [""2019-01-30T12:01:02.0000000Z""]," +
+                @"""MyEnumArray"" : [2]," + // int by default
+                @"""MyStringList"" : [""Hello""]," +
+                @"""MyStringIEnumerableT"" : [""Hello""]," +
+                @"""MyStringIListT"" : [""Hello""]," +
+                @"""MyStringICollectionT"" : [""Hello""]," +
+                @"""MyStringIReadOnlyCollectionT"" : [""Hello""]," +
+                @"""MyStringIReadOnlyListT"" : [""Hello""]" +
+                @"}";
+
+        public static readonly byte[] s_data = Encoding.UTF8.GetBytes(s_json);
+
+        public void Initialize()
+        {
+            MyInt16 = (short)1;
+            MyInt32 = (int)2;
+            MyInt64 = (long)3;
+            MyUInt16 = (ushort)4;
+            MyUInt32 = (uint)5;
+            MyUInt64 = (ulong)6;
+            MyByte = (byte)7;
+            MySByte = (sbyte)8;
+            MyChar = 'a';
+            MyString = "Hello";
+            MyBooleanTrue = true;
+            MyBooleanFalse = false;
+            MySingle = 1.1f;
+            MyDouble = 2.2d;
+            MyDecimal = 3.3m;
+            MyDateTime = new DateTime(2019, 1, 30, 12, 1, 2, DateTimeKind.Utc);
+            MyEnum = SampleEnum.Two;
+
+            MyInt16Array = new short[] { 1 };
+            MyInt32Array = new int[] { 2 };
+            MyInt64Array = new long[] { 3 };
+            MyUInt16Array = new ushort[] { 4 };
+            MyUInt32Array = new uint[] { 5 };
+            MyUInt64Array = new ulong[] { 6 };
+            MyByteArray = new byte[] { 7 };
+            MySByteArray = new sbyte[] { 8 };
+            MyCharArray = new char[] { 'a' };
+            MyStringArray = new string[] { "Hello" };
+            MyBooleanTrueArray = new bool[] { true };
+            MyBooleanFalseArray = new bool[] { false };
+            MySingleArray = new float[] { 1.1f };
+            MyDoubleArray = new double[] { 2.2d };
+            MyDecimalArray = new decimal[] { 3.3m };
+            MyDateTimeArray = new DateTime[] { new DateTime(2019, 1, 30, 12, 1, 2, DateTimeKind.Utc) };
+            MyEnumArray = new SampleEnum[] { SampleEnum.Two };
+
+            MyStringList = new List<string>() { "Hello" };
+            MyStringIEnumerableT = new string[] { "Hello" };
+            MyStringIListT = new string[] { "Hello" };
+            MyStringICollectionT = new string[] { "Hello" };
+            MyStringIReadOnlyCollectionT = new string[] { "Hello" };
+            MyStringIReadOnlyListT = new string[] { "Hello" };
+        }
+
+        public void Verify()
+        {
+            Assert.Equal((short)1, MyInt16);
+            Assert.Equal((int)2, MyInt32);
+            Assert.Equal((long)3, MyInt64);
+            Assert.Equal((ushort)4, MyUInt16);
+            Assert.Equal((uint)5, MyUInt32);
+            Assert.Equal((ulong)6, MyUInt64);
+            Assert.Equal((byte)7, MyByte);
+            Assert.Equal((sbyte)8, MySByte);
+            Assert.Equal('a', MyChar);
+            Assert.Equal("Hello", MyString);
+            Assert.Equal(3.3m, MyDecimal);
+            Assert.Equal(false, MyBooleanFalse);
+            Assert.Equal(true, MyBooleanTrue);
+            Assert.Equal(1.1f, MySingle);
+            Assert.Equal(2.2d, MyDouble);
+            Assert.Equal(new DateTime(2019, 1, 30, 12, 1, 2, DateTimeKind.Utc), MyDateTime);
+            Assert.Equal(SampleEnum.Two, MyEnum);
+
+            Assert.Equal((short)1, ((short[])MyInt16Array)[0]);
+            Assert.Equal((int)2, ((int[])MyInt32Array)[0]);
+            Assert.Equal((long)3, ((long[])MyInt64Array)[0]);
+            Assert.Equal((ushort)4, ((ushort[])MyUInt16Array)[0]);
+            Assert.Equal((uint)5, ((uint[])MyUInt32Array)[0]);
+            Assert.Equal((ulong)6, ((ulong[])MyUInt64Array)[0]);
+            Assert.Equal((byte)7, ((byte[])MyByteArray)[0]);
+            Assert.Equal((sbyte)8, ((sbyte[])MySByteArray)[0]);
+            Assert.Equal('a', ((char[])MyCharArray)[0]);
+            Assert.Equal("Hello", ((string[])MyStringArray)[0]);
+            Assert.Equal(3.3m, ((decimal[])MyDecimalArray)[0]);
+            Assert.Equal(false, ((bool[])MyBooleanFalseArray)[0]);
+            Assert.Equal(true, ((bool[])MyBooleanTrueArray)[0]);
+            Assert.Equal(1.1f, ((float[])MySingleArray)[0]);
+            Assert.Equal(2.2d, ((double[])MyDoubleArray)[0]);
+            Assert.Equal(new DateTime(2019, 1, 30, 12, 1, 2, DateTimeKind.Utc), ((DateTime[])MyDateTimeArray)[0]);
+            Assert.Equal(SampleEnum.Two, ((SampleEnum[])MyEnumArray)[0]);
+
+            Assert.Equal("Hello", ((List<string>)MyStringList)[0]);
+            Assert.Equal("Hello", ((IEnumerable<string>)MyStringIEnumerableT).First());
+            Assert.Equal("Hello", ((IList<string>)MyStringIListT)[0]);
+            Assert.Equal("Hello", ((ICollection<string>)MyStringICollectionT).First());
+            Assert.Equal("Hello", ((IReadOnlyCollection<string>)MyStringIReadOnlyCollectionT).First());
+            Assert.Equal("Hello", ((IReadOnlyList<string>)MyStringIReadOnlyListT)[0]);
+        }
+    }
+}
index 4701d52..f6c7195 100644 (file)
@@ -20,520 +20,6 @@ namespace System.Text.Json.Serialization.Tests
         Two = 2
     }
 
-    public class SimpleTestClass : ITestClass
-    {
-        public short MyInt16 { get; set; }
-        public int MyInt32 { get; set; }
-        public long MyInt64 { get; set; }
-        public ushort MyUInt16 { get; set; }
-        public uint MyUInt32 { get; set; }
-        public ulong MyUInt64 { get; set; }
-        public byte MyByte { get; set; }
-        public sbyte MySByte { get; set; }
-        public char MyChar { get; set; }
-        public string MyString { get; set; }
-        public decimal MyDecimal { get; set; }
-        public bool MyBooleanTrue { get; set; }
-        public bool MyBooleanFalse { get; set; }
-        public float MySingle { get; set; }
-        public double MyDouble { get; set; }
-        public DateTime MyDateTime { get; set; }
-        public DateTimeOffset MyDateTimeOffset { get; set; }
-        public SampleEnum MyEnum { get; set; }
-        public short[] MyInt16Array { get; set; }
-        public int[] MyInt32Array { get; set; }
-        public long[] MyInt64Array { get; set; }
-        public ushort[] MyUInt16Array { get; set; }
-        public uint[] MyUInt32Array { get; set; }
-        public ulong[] MyUInt64Array { get; set; }
-        public byte[] MyByteArray { get; set; }
-        public sbyte[] MySByteArray { get; set; }
-        public char[] MyCharArray { get; set; }
-        public string[] MyStringArray { get; set; }
-        public decimal[] MyDecimalArray { get; set; }
-        public bool[] MyBooleanTrueArray { get; set; }
-        public bool[] MyBooleanFalseArray { get; set; }
-        public float[] MySingleArray { get; set; }
-        public double[] MyDoubleArray { get; set; }
-        public DateTime[] MyDateTimeArray { get; set; }
-        public DateTimeOffset[] MyDateTimeOffsetArray { get; set; }
-        public SampleEnum[] MyEnumArray { get; set; }
-        public List<string> MyStringList { get; set; }
-        public IEnumerable<string> MyStringIEnumerableT { get; set; }
-        public IList<string> MyStringIListT { get; set; }
-        public ICollection<string> MyStringICollectionT { get; set; }
-        public IReadOnlyCollection<string> MyStringIReadOnlyCollectionT { get; set; }
-        public IReadOnlyList<string> MyStringIReadOnlyListT { get; set; }
-
-        public static readonly string s_json = $"{{{s_partialJsonProperties},{s_partialJsonArrays}}}";
-        public static readonly string s_json_flipped = $"{{{s_partialJsonArrays},{s_partialJsonProperties}}}";
-
-        private const string s_partialJsonProperties =
-                @"""MyInt16"" : 1," +
-                @"""MyInt32"" : 2," +
-                @"""MyInt64"" : 3," +
-                @"""MyUInt16"" : 4," +
-                @"""MyUInt32"" : 5," +
-                @"""MyUInt64"" : 6," +
-                @"""MyByte"" : 7," +
-                @"""MySByte"" : 8," +
-                @"""MyChar"" : ""a""," +
-                @"""MyString"" : ""Hello""," +
-                @"""MyBooleanTrue"" : true," +
-                @"""MyBooleanFalse"" : false," +
-                @"""MySingle"" : 1.1," +
-                @"""MyDouble"" : 2.2," +
-                @"""MyDecimal"" : 3.3," +
-                @"""MyDateTime"" : ""2019-01-30T12:01:02.0000000Z""," +
-                @"""MyDateTimeOffset"" : ""2019-01-30T12:01:02.0000000+01:00""," +
-                @"""MyEnum"" : 2"; // int by default
-
-        private const string s_partialJsonArrays =
-                @"""MyInt16Array"" : [1]," +
-                @"""MyInt32Array"" : [2]," +
-                @"""MyInt64Array"" : [3]," +
-                @"""MyUInt16Array"" : [4]," +
-                @"""MyUInt32Array"" : [5]," +
-                @"""MyUInt64Array"" : [6]," +
-                @"""MyByteArray"" : [7]," +
-                @"""MySByteArray"" : [8]," +
-                @"""MyCharArray"" : [""a""]," +
-                @"""MyStringArray"" : [""Hello""]," +
-                @"""MyBooleanTrueArray"" : [true]," +
-                @"""MyBooleanFalseArray"" : [false]," +
-                @"""MySingleArray"" : [1.1]," +
-                @"""MyDoubleArray"" : [2.2]," +
-                @"""MyDecimalArray"" : [3.3]," +
-                @"""MyDateTimeArray"" : [""2019-01-30T12:01:02.0000000Z""]," +
-                @"""MyDateTimeOffsetArray"" : [""2019-01-30T12:01:02.0000000+01:00""]," +
-                @"""MyEnumArray"" : [2]," + // int by default
-                @"""MyStringList"" : [""Hello""]," +
-                @"""MyStringIEnumerableT"" : [""Hello""]," +
-                @"""MyStringIListT"" : [""Hello""]," +
-                @"""MyStringICollectionT"" : [""Hello""]," +
-                @"""MyStringIReadOnlyCollectionT"" : [""Hello""]," +
-                @"""MyStringIReadOnlyListT"" : [""Hello""]";
-
-        public static readonly byte[] s_data = Encoding.UTF8.GetBytes(s_json);
-
-        public void Initialize()
-        {
-            MyInt16 = 1;
-            MyInt32 = 2;
-            MyInt64 = 3;
-            MyUInt16 = 4;
-            MyUInt32 = 5;
-            MyUInt64 = 6;
-            MyByte = 7;
-            MySByte = 8;
-            MyChar = 'a';
-            MyString = "Hello";
-            MyBooleanTrue = true;
-            MyBooleanFalse = false;
-            MySingle = 1.1f;
-            MyDouble = 2.2d;
-            MyDecimal = 3.3m;
-            MyDateTime = new DateTime(2019, 1, 30, 12, 1, 2, DateTimeKind.Utc);
-            MyDateTimeOffset = new DateTimeOffset(2019, 1, 30, 12, 1, 2, new TimeSpan(1, 0, 0));
-            MyEnum = SampleEnum.Two;
-
-            MyInt16Array = new short[] { 1 };
-            MyInt32Array = new int[] { 2 };
-            MyInt64Array = new long[] { 3 };
-            MyUInt16Array = new ushort[] { 4 };
-            MyUInt32Array = new uint[] { 5 };
-            MyUInt64Array = new ulong[] { 6 };
-            MyByteArray = new byte[] { 7 };
-            MySByteArray = new sbyte[] { 8 };
-            MyCharArray = new char[] { 'a' };
-            MyStringArray = new string[] { "Hello" };
-            MyBooleanTrueArray = new bool[] { true };
-            MyBooleanFalseArray = new bool[] { false };
-            MySingleArray = new float[] { 1.1f };
-            MyDoubleArray = new double[] { 2.2d };
-            MyDecimalArray = new decimal[] { 3.3m };
-            MyDateTimeArray = new DateTime[] { new DateTime(2019, 1, 30, 12, 1, 2, DateTimeKind.Utc) };
-            MyDateTimeOffsetArray = new DateTimeOffset[] { new DateTimeOffset(2019, 1, 30, 12, 1, 2, new TimeSpan(1, 0, 0)) };
-            MyEnumArray = new SampleEnum[] { SampleEnum.Two };
-
-            MyStringList = new List<string>() { "Hello" };
-            MyStringIEnumerableT = new string[] { "Hello" };
-            MyStringIListT = new string[] { "Hello" };
-            MyStringICollectionT = new string[] { "Hello" };
-            MyStringIReadOnlyCollectionT = new string[] { "Hello" };
-            MyStringIReadOnlyListT = new string[] { "Hello" };
-        }
-
-        public void Verify()
-        {
-            Assert.Equal((short)1, MyInt16);
-            Assert.Equal((int)2, MyInt32);
-            Assert.Equal((long)3, MyInt64);
-            Assert.Equal((ushort)4, MyUInt16);
-            Assert.Equal((uint)5, MyUInt32);
-            Assert.Equal((ulong)6, MyUInt64);
-            Assert.Equal((byte)7, MyByte);
-            Assert.Equal((sbyte)8, MySByte);
-            Assert.Equal('a', MyChar);
-            Assert.Equal("Hello", MyString);
-            Assert.Equal(3.3m, MyDecimal);
-            Assert.Equal(false, MyBooleanFalse);
-            Assert.Equal(true, MyBooleanTrue);
-            Assert.Equal(1.1f, MySingle);
-            Assert.Equal(2.2d, MyDouble);
-            Assert.Equal(new DateTime(2019, 1, 30, 12, 1, 2, DateTimeKind.Utc), MyDateTime);
-            Assert.Equal(new DateTimeOffset(2019, 1, 30, 12, 1, 2, new TimeSpan(1, 0, 0)), MyDateTimeOffset);
-            Assert.Equal(SampleEnum.Two, MyEnum);
-
-            Assert.Equal((short)1, MyInt16Array[0]);
-            Assert.Equal((int)2, MyInt32Array[0]);
-            Assert.Equal((long)3, MyInt64Array[0]);
-            Assert.Equal((ushort)4, MyUInt16Array[0]);
-            Assert.Equal((uint)5, MyUInt32Array[0]);
-            Assert.Equal((ulong)6, MyUInt64Array[0]);
-            Assert.Equal((byte)7, MyByteArray[0]);
-            Assert.Equal((sbyte)8, MySByteArray[0]);
-            Assert.Equal('a', MyCharArray[0]);
-            Assert.Equal("Hello", MyStringArray[0]);
-            Assert.Equal(3.3m, MyDecimalArray[0]);
-            Assert.Equal(false, MyBooleanFalseArray[0]);
-            Assert.Equal(true, MyBooleanTrueArray[0]);
-            Assert.Equal(1.1f, MySingleArray[0]);
-            Assert.Equal(2.2d, MyDoubleArray[0]);
-            Assert.Equal(new DateTime(2019, 1, 30, 12, 1, 2, DateTimeKind.Utc), MyDateTimeArray[0]);
-            Assert.Equal(new DateTimeOffset(2019, 1, 30, 12, 1, 2, new TimeSpan(1, 0, 0)), MyDateTimeOffsetArray[0]);
-            Assert.Equal(SampleEnum.Two, MyEnumArray[0]);
-
-            Assert.Equal("Hello", MyStringList[0]);
-            Assert.Equal("Hello", MyStringIEnumerableT.First());
-            Assert.Equal("Hello", MyStringIListT[0]);
-            Assert.Equal("Hello", MyStringICollectionT.First());
-            Assert.Equal("Hello", MyStringIReadOnlyCollectionT.First());
-            Assert.Equal("Hello", MyStringIReadOnlyListT[0]);
-        }
-    }
-
-    public class SimpleTestClassWithObject : ITestClass
-    {
-        public object MyInt16 { get; set; }
-        public object MyInt32 { get; set; }
-        public object MyInt64 { get; set; }
-        public object MyUInt16 { get; set; }
-        public object MyUInt32 { get; set; }
-        public object MyUInt64 { get; set; }
-        public object MyByte { get; set; }
-        public object MySByte { get; set; }
-        public object MyChar { get; set; }
-        public object MyString { get; set; }
-        public object MyDecimal { get; set; }
-        public object MyBooleanTrue { get; set; }
-        public object MyBooleanFalse { get; set; }
-        public object MySingle { get; set; }
-        public object MyDouble { get; set; }
-        public object MyDateTime { get; set; }
-        public object MyEnum { get; set; }
-        public object MyInt16Array { get; set; }
-        public object MyInt32Array { get; set; }
-        public object MyInt64Array { get; set; }
-        public object MyUInt16Array { get; set; }
-        public object MyUInt32Array { get; set; }
-        public object MyUInt64Array { get; set; }
-        public object MyByteArray { get; set; }
-        public object MySByteArray { get; set; }
-        public object MyCharArray { get; set; }
-        public object MyStringArray { get; set; }
-        public object MyDecimalArray { get; set; }
-        public object MyBooleanTrueArray { get; set; }
-        public object MyBooleanFalseArray { get; set; }
-        public object MySingleArray { get; set; }
-        public object MyDoubleArray { get; set; }
-        public object MyDateTimeArray { get; set; }
-        public object MyEnumArray { get; set; }
-        public object MyStringList { get; set; }
-        public object MyStringIEnumerableT { get; set; }
-        public object MyStringIListT { get; set; }
-        public object MyStringICollectionT { get; set; }
-        public object MyStringIReadOnlyCollectionT { get; set; }
-        public object MyStringIReadOnlyListT { get; set; }
-
-        public static readonly string s_json =
-                @"{" +
-                @"""MyInt16"" : 1," +
-                @"""MyInt32"" : 2," +
-                @"""MyInt64"" : 3," +
-                @"""MyUInt16"" : 4," +
-                @"""MyUInt32"" : 5," +
-                @"""MyUInt64"" : 6," +
-                @"""MyByte"" : 7," +
-                @"""MySByte"" : 8," +
-                @"""MyChar"" : ""a""," +
-                @"""MyString"" : ""Hello""," +
-                @"""MyBooleanTrue"" : true," +
-                @"""MyBooleanFalse"" : false," +
-                @"""MySingle"" : 1.1," +
-                @"""MyDouble"" : 2.2," +
-                @"""MyDecimal"" : 3.3," +
-                @"""MyDateTime"" : ""2019-01-30T12:01:02.0000000Z""," +
-                @"""MyEnum"" : 2," + // int by default
-                @"""MyInt16Array"" : [1]," +
-                @"""MyInt32Array"" : [2]," +
-                @"""MyInt64Array"" : [3]," +
-                @"""MyUInt16Array"" : [4]," +
-                @"""MyUInt32Array"" : [5]," +
-                @"""MyUInt64Array"" : [6]," +
-                @"""MyByteArray"" : [7]," +
-                @"""MySByteArray"" : [8]," +
-                @"""MyCharArray"" : [""a""]," +
-                @"""MyStringArray"" : [""Hello""]," +
-                @"""MyBooleanTrueArray"" : [true]," +
-                @"""MyBooleanFalseArray"" : [false]," +
-                @"""MySingleArray"" : [1.1]," +
-                @"""MyDoubleArray"" : [2.2]," +
-                @"""MyDecimalArray"" : [3.3]," +
-                @"""MyDateTimeArray"" : [""2019-01-30T12:01:02.0000000Z""]," +
-                @"""MyEnumArray"" : [2]," + // int by default
-                @"""MyStringList"" : [""Hello""]," +
-                @"""MyStringIEnumerableT"" : [""Hello""]," +
-                @"""MyStringIListT"" : [""Hello""]," +
-                @"""MyStringICollectionT"" : [""Hello""]," +
-                @"""MyStringIReadOnlyCollectionT"" : [""Hello""]," +
-                @"""MyStringIReadOnlyListT"" : [""Hello""]" +
-                @"}";
-
-        public static readonly byte[] s_data = Encoding.UTF8.GetBytes(s_json);
-
-        public void Initialize()
-        {
-            MyInt16 = (short)1;
-            MyInt32 = (int)2;
-            MyInt64 = (long)3;
-            MyUInt16 = (ushort)4;
-            MyUInt32 = (uint)5;
-            MyUInt64 = (ulong)6;
-            MyByte = (byte)7;
-            MySByte =(sbyte) 8;
-            MyChar = 'a';
-            MyString = "Hello";
-            MyBooleanTrue = true;
-            MyBooleanFalse = false;
-            MySingle = 1.1f;
-            MyDouble = 2.2d;
-            MyDecimal = 3.3m;
-            MyDateTime = new DateTime(2019, 1, 30, 12, 1, 2, DateTimeKind.Utc);
-            MyEnum = SampleEnum.Two;
-
-            MyInt16Array = new short[] { 1 };
-            MyInt32Array = new int[] { 2 };
-            MyInt64Array = new long[] { 3 };
-            MyUInt16Array = new ushort[] { 4 };
-            MyUInt32Array = new uint[] { 5 };
-            MyUInt64Array = new ulong[] { 6 };
-            MyByteArray = new byte[] { 7 };
-            MySByteArray = new sbyte[] { 8 };
-            MyCharArray = new char[] { 'a' };
-            MyStringArray = new string[] { "Hello" };
-            MyBooleanTrueArray = new bool[] { true };
-            MyBooleanFalseArray = new bool[] { false };
-            MySingleArray = new float[] { 1.1f };
-            MyDoubleArray = new double[] { 2.2d };
-            MyDecimalArray = new decimal[] { 3.3m };
-            MyDateTimeArray = new DateTime[] { new DateTime(2019, 1, 30, 12, 1, 2, DateTimeKind.Utc) };
-            MyEnumArray = new SampleEnum[] { SampleEnum.Two };
-
-            MyStringList = new List<string>() { "Hello" };
-            MyStringIEnumerableT = new string[] { "Hello" };
-            MyStringIListT = new string[] { "Hello" };
-            MyStringICollectionT = new string[] { "Hello" };
-            MyStringIReadOnlyCollectionT = new string[] { "Hello" };
-            MyStringIReadOnlyListT = new string[] { "Hello" };
-        }
-
-        public void Verify()
-        {
-            Assert.Equal((short)1, MyInt16);
-            Assert.Equal((int)2, MyInt32);
-            Assert.Equal((long)3, MyInt64);
-            Assert.Equal((ushort)4, MyUInt16);
-            Assert.Equal((uint)5, MyUInt32);
-            Assert.Equal((ulong)6, MyUInt64);
-            Assert.Equal((byte)7, MyByte);
-            Assert.Equal((sbyte)8, MySByte);
-            Assert.Equal('a', MyChar);
-            Assert.Equal("Hello", MyString);
-            Assert.Equal(3.3m, MyDecimal);
-            Assert.Equal(false, MyBooleanFalse);
-            Assert.Equal(true, MyBooleanTrue);
-            Assert.Equal(1.1f, MySingle);
-            Assert.Equal(2.2d, MyDouble);
-            Assert.Equal(new DateTime(2019, 1, 30, 12, 1, 2, DateTimeKind.Utc), MyDateTime);
-            Assert.Equal(SampleEnum.Two, MyEnum);
-
-            Assert.Equal((short)1, ((short[])MyInt16Array)[0]);
-            Assert.Equal((int)2, ((int[])MyInt32Array)[0]);
-            Assert.Equal((long)3, ((long[])MyInt64Array)[0]);
-            Assert.Equal((ushort)4, ((ushort[])MyUInt16Array)[0]);
-            Assert.Equal((uint)5, ((uint[])MyUInt32Array)[0]);
-            Assert.Equal((ulong)6, ((ulong[])MyUInt64Array)[0]);
-            Assert.Equal((byte)7, ((byte[])MyByteArray)[0]);
-            Assert.Equal((sbyte)8, ((sbyte[])MySByteArray)[0]);
-            Assert.Equal('a', ((char[])MyCharArray)[0]);
-            Assert.Equal("Hello", ((string[])MyStringArray)[0]);
-            Assert.Equal(3.3m, ((decimal[])MyDecimalArray)[0]);
-            Assert.Equal(false, ((bool[])MyBooleanFalseArray)[0]);
-            Assert.Equal(true, ((bool[])MyBooleanTrueArray)[0]);
-            Assert.Equal(1.1f, ((float[])MySingleArray)[0]);
-            Assert.Equal(2.2d, ((double[])MyDoubleArray)[0]);
-            Assert.Equal(new DateTime(2019, 1, 30, 12, 1, 2, DateTimeKind.Utc), ((DateTime[])MyDateTimeArray)[0]);
-            Assert.Equal(SampleEnum.Two, ((SampleEnum[])MyEnumArray)[0]);
-
-            Assert.Equal("Hello", ((List<string>)MyStringList)[0]);
-            Assert.Equal("Hello", ((IEnumerable<string>)MyStringIEnumerableT).First());
-            Assert.Equal("Hello", ((IList<string>)MyStringIListT)[0]);
-            Assert.Equal("Hello", ((ICollection<string>)MyStringICollectionT).First());
-            Assert.Equal("Hello", ((IReadOnlyCollection<string>)MyStringIReadOnlyCollectionT).First());
-            Assert.Equal("Hello", ((IReadOnlyList<string>)MyStringIReadOnlyListT)[0]);
-        }
-    }
-
-    public abstract class SimpleBaseClassWithNullables
-    {
-        public short? MyInt16 { get; set; }
-        public int? MyInt32 { get; set; }
-        public long? MyInt64 { get; set; }
-        public ushort? MyUInt16 { get; set; }
-        public uint? MyUInt32 { get; set; }
-        public ulong? MyUInt64 { get; set; }
-        public byte? MyByte { get; set; }
-        public sbyte? MySByte { get; set; }
-        public char? MyChar { get; set; }
-        public decimal? MyDecimal { get; set; }
-        public bool? MyBooleanTrue { get; set; }
-        public bool? MyBooleanFalse { get; set; }
-        public float? MySingle { get; set; }
-        public double? MyDouble { get; set; }
-        public DateTime? MyDateTime { get; set; }
-        public DateTimeOffset? MyDateTimeOffset { get; set; }
-        public SampleEnum? MyEnum { get; set; }
-    }
-
-    public class SimpleTestClassWithNulls : SimpleBaseClassWithNullables, ITestClass
-    {
-        public void Initialize()
-        {
-        }
-
-        public void Verify()
-        {
-            Assert.Null(MyInt16);
-            Assert.Null(MyInt32);
-            Assert.Null(MyInt64);
-            Assert.Null(MyUInt16);
-            Assert.Null(MyUInt32);
-            Assert.Null(MyUInt64);
-            Assert.Null(MyByte);
-            Assert.Null(MySByte);
-            Assert.Null(MyChar);
-            Assert.Null(MyDecimal);
-            Assert.Null(MyBooleanFalse);
-            Assert.Null(MyBooleanTrue);
-            Assert.Null(MySingle);
-            Assert.Null(MyDouble);
-            Assert.Null(MyDateTime);
-            Assert.Null(MyDateTimeOffset);
-            Assert.Null(MyEnum);
-        }
-        public static readonly string s_json =
-                @"{" +
-                @"""MyInt16"" : null," +
-                @"""MyInt32"" : null," +
-                @"""MyInt64"" : null," +
-                @"""MyUInt16"" : null," +
-                @"""MyUInt32"" : null," +
-                @"""MyUInt64"" : null," +
-                @"""MyByte"" : null," +
-                @"""MySByte"" : null," +
-                @"""MyChar"" : null," +
-                @"""MyBooleanTrue"" : null," +
-                @"""MyBooleanFalse"" : null," +
-                @"""MySingle"" : null," +
-                @"""MyDouble"" : null," +
-                @"""MyDecimal"" : null," +
-                @"""MyDateTime"" : null," +
-                @"""MyDateTimeOffset"" : null," +
-                @"""MyEnum"" : null" +
-                @"}";
-
-        public static readonly byte[] s_data = Encoding.UTF8.GetBytes(s_json);
-    }
-
-    public class SimpleTestClassWithNullables : SimpleBaseClassWithNullables, ITestClass
-    {
-        public static readonly string s_json =
-                @"{" +
-                @"""MyInt16"" : 1," +
-                @"""MyInt32"" : 2," +
-                @"""MyInt64"" : 3," +
-                @"""MyUInt16"" : 4," +
-                @"""MyUInt32"" : 5," +
-                @"""MyUInt64"" : 6," +
-                @"""MyByte"" : 7," +
-                @"""MySByte"" : 8," +
-                @"""MyChar"" : ""a""," +
-                @"""MyBooleanTrue"" : true," +
-                @"""MyBooleanFalse"" : false," +
-                @"""MySingle"" : 1.1," +
-                @"""MyDouble"" : 2.2," +
-                @"""MyDecimal"" : 3.3," +
-                @"""MyDateTime"" : ""2019-01-30T12:01:02.0000000Z""," +
-                @"""MyDateTimeOffset"" : ""2019-01-30T12:01:02.0000000+01:00""," +
-                @"""MyEnum"" : 2" + // int by default
-                @"}";
-
-        public static readonly byte[] s_data = Encoding.UTF8.GetBytes(s_json);
-
-        public void Initialize()
-        {
-            MyInt16 = 1;
-            MyInt32 = 2;
-            MyInt64 = 3;
-            MyUInt16 = 4;
-            MyUInt32 = 5;
-            MyUInt64 = 6;
-            MyByte = 7;
-            MySByte = 8;
-            MyChar = 'a';
-            MyBooleanTrue = true;
-            MyBooleanFalse = false;
-            MySingle = 1.1f;
-            MyDouble = 2.2d;
-            MyDecimal = 3.3m;
-            MyDateTime = new DateTime(2019, 1, 30, 12, 1, 2, DateTimeKind.Utc);
-            MyDateTimeOffset = new DateTimeOffset(2019, 1, 30, 12, 1, 2, new TimeSpan(1, 0, 0));
-            MyEnum = SampleEnum.Two;
-        }
-
-        public void Verify()
-        {
-            Assert.Equal(MyInt16, (short)1);
-            Assert.Equal(MyInt32, (int)2);
-            Assert.Equal(MyInt64, (long)3);
-            Assert.Equal(MyUInt16, (ushort)4);
-            Assert.Equal(MyUInt32, (uint)5);
-            Assert.Equal(MyUInt64, (ulong)6);
-            Assert.Equal(MyByte, (byte)7);
-            Assert.Equal(MySByte, (sbyte)8);
-            Assert.Equal(MyChar, 'a');
-            Assert.Equal(MyDecimal, 3.3m);
-            Assert.Equal(MyBooleanFalse, false);
-            Assert.Equal(MyBooleanTrue, true);
-            Assert.Equal(MySingle, 1.1f);
-            Assert.Equal(MyDouble, 2.2d);
-            Assert.Equal(MyDateTime, new DateTime(2019, 1, 30, 12, 1, 2, DateTimeKind.Utc));
-            Assert.Equal(MyDateTimeOffset, new DateTimeOffset(2019, 1, 30, 12, 1, 2, new TimeSpan(1, 0, 0)));
-            Assert.Equal(MyEnum, SampleEnum.Two);
-        }
-    }
-
     public class TestClassWithNull
     {
         public string MyString { get; set; }
index 15efaa0..fb55335 100644 (file)
@@ -40,6 +40,9 @@
     <Compile Include="Serialization\Stream.WriteTests.cs" />
     <Compile Include="Serialization\TestClasses.cs" />
     <Compile Include="Serialization\TestClasses.Polymorphic.cs" />
+    <Compile Include="Serialization\TestClasses.SimpleTestClass.cs" />
+    <Compile Include="Serialization\TestClasses.SimpleTestClassWithNullables.cs" />
+    <Compile Include="Serialization\TestClasses.SimpleTestClassWithObject.cs" />
     <Compile Include="Serialization\TestData.cs" />
     <Compile Include="Serialization\Value.ReadTests.cs" />
     <Compile Include="Serialization\Value.WriteTests.cs" />