<value>Expected depth to be zero at the end of the JSON payload. There is an open JSON object or array that should be closed.</value>
</data>
<data name="DeserializeCannotBeNull" xml:space="preserve">
- <value>The JSON value from {0} cannot be null.</value>
+ <value>The JSON value cannot be null.</value>
</data>
<data name="DeserializeDataRemaining" xml:space="preserve">
<value>The provided data of length {0} has remaining bytes {1}.</value>
// Convert interfaces to concrete types.
if (propertyType.IsInterface && jsonInfo.ClassType == ClassType.Dictionary)
{
- Type newPropertyType = jsonInfo.ElementClassInfo.GetPolicyProperty().GetConcreteType(propertyType);
- if (propertyType != newPropertyType)
+ // If a polymorphic case, we have to wait until run-time values are processed.
+ if (jsonInfo.ElementClassInfo.ClassType != ClassType.Unknown)
{
- jsonInfo = CreateProperty(propertyType, newPropertyType, propertyInfo, classType, options);
+ Type newPropertyType = jsonInfo.ElementClassInfo.GetPolicyProperty().GetDictionaryConcreteType();
+ if (propertyType != newPropertyType)
+ {
+ jsonInfo = CreateProperty(propertyType, newPropertyType, propertyInfo, classType, options);
+ }
}
}
{
elementType = args[1];
}
- else if (args.Length >= 1) // It is >= 1 in case there is an IEnumerable<T, TSomeExtension>.
+ else if (GetClassType(propertyType) == ClassType.Enumerable && args.Length >= 1) // It is >= 1 in case there is an IEnumerable<T, TSomeExtension>.
{
- Debug.Assert(GetClassType(propertyType) == ClassType.Enumerable);
elementType = args[0];
}
}
return (TAttribute)PropertyInfo?.GetCustomAttribute(typeof(TAttribute), inherit: false);
}
- public abstract void ApplyNullValue(JsonSerializerOptions options, ref ReadStack state, ref Utf8JsonReader reader);
-
public abstract IList CreateConverterList();
- public abstract Type GetConcreteType(Type interfaceType);
+ public abstract Type GetDictionaryConcreteType();
public abstract void Read(JsonTokenType tokenType, JsonSerializerOptions options, ref ReadStack state, ref Utf8JsonReader reader);
public abstract void ReadEnumerable(JsonTokenType tokenType, JsonSerializerOptions options, ref ReadStack state, ref Utf8JsonReader reader);
public abstract void Write(JsonSerializerOptions options, ref WriteStackFrame current, Utf8JsonWriter writer);
- public abstract void WriteDictionary(JsonSerializerOptions options, ref WriteStackFrame current, Utf8JsonWriter writer);
+ public virtual void WriteDictionary(JsonSerializerOptions options, ref WriteStackFrame current, Utf8JsonWriter writer) { }
public abstract void WriteEnumerable(JsonSerializerOptions options, ref WriteStackFrame current, Utf8JsonWriter writer);
}
}
return new List<TDeclaredProperty>();
}
- // Map interfaces to a well-known implementation.
- public override Type GetConcreteType(Type interfaceType)
+ public override Type GetDictionaryConcreteType()
{
- if (interfaceType.IsAssignableFrom(typeof(IDictionary<string, TRuntimeProperty>)) ||
- interfaceType.IsAssignableFrom(typeof(IReadOnlyDictionary<string, TRuntimeProperty>)))
- {
- return typeof(Dictionary<string, TRuntimeProperty>);
- }
-
- return interfaceType;
+ return typeof(Dictionary<string, TRuntimeProperty>);
}
}
}
JsonSerializer.ApplyValueToEnumerable(ref value, options, ref state, ref reader);
}
- public override void ApplyNullValue(JsonSerializerOptions options, ref ReadStack state, ref Utf8JsonReader reader)
- {
- Debug.Assert(state.Current.JsonPropertyInfo != null);
- state.Current.JsonPropertyInfo.SetValueAsObject(state.Current.ReturnValue, value : null);
- }
-
- // todo: have the caller check if current.Enumerator != null and call WriteEnumerable of the underlying property directly to avoid an extra virtual call.
public override void Write(JsonSerializerOptions options, ref WriteStackFrame current, Utf8JsonWriter writer)
{
- if (current.Enumerator != null)
- {
- // Forward the setter to the value-based JsonPropertyInfo.
- JsonPropertyInfo propertyInfo = ElementClassInfo.GetPolicyProperty();
- propertyInfo.WriteEnumerable(options, ref current, writer);
- }
- else if (ShouldSerialize)
+ Debug.Assert(current.Enumerator == null);
+
+ if (ShouldSerialize)
{
TRuntimeProperty value;
if (_isPropertyPolicy)
if (value == null)
{
- if (_escapedName == null)
- {
- writer.WriteNullValue();
- }
- else if (!IgnoreNullValues)
+ Debug.Assert(_escapedName != null);
+
+ if (!IgnoreNullValues)
{
writer.WriteNull(_escapedName);
}
JsonSerializer.WriteDictionary(ValueConverter, options, ref current, writer);
}
-
public override void WriteEnumerable(JsonSerializerOptions options, ref WriteStackFrame current, Utf8JsonWriter writer)
{
if (ValueConverter != null)
public override void Read(JsonTokenType tokenType, JsonSerializerOptions options, ref ReadStack state, ref Utf8JsonReader reader)
{
- if (ElementClassInfo != null)
- {
- // Forward the setter to the value-based JsonPropertyInfo.
- JsonPropertyInfo propertyInfo = ElementClassInfo.GetPolicyProperty();
- propertyInfo.ReadEnumerable(tokenType, options, ref state, ref reader);
- }
- else if (ShouldDeserialize)
+ Debug.Assert(ElementClassInfo == null);
+
+ if (ShouldDeserialize)
{
if (ValueConverter != null)
{
return;
}
- // Converting to TProperty? here lets us share a common ApplyValue() with ApplyNullValue().
TProperty? nullableValue = new TProperty?(value);
JsonSerializer.ApplyValueToEnumerable(ref nullableValue, options, ref state, ref reader);
}
- public override void ApplyNullValue(JsonSerializerOptions options, ref ReadStack state, ref Utf8JsonReader reader)
- {
- TProperty? nullableValue = null;
- JsonSerializer.ApplyValueToEnumerable(ref nullableValue, options, ref state, ref reader);
- }
-
- // todo: have the caller check if current.Enumerator != null and call WriteEnumerable of the underlying property directly to avoid an extra virtual call.
public override void Write(JsonSerializerOptions options, ref WriteStackFrame current, Utf8JsonWriter writer)
{
if (current.Enumerator != null)
if (value == null)
{
- if (_escapedName == null)
- {
- writer.WriteNullValue();
- }
- else if (!IgnoreNullValues)
+ Debug.Assert(_escapedName != null);
+
+ if (!IgnoreNullValues)
{
writer.WriteNull(_escapedName);
}
}
}
- public override void WriteDictionary(JsonSerializerOptions options, ref WriteStackFrame current, Utf8JsonWriter writer)
- {
- JsonSerializer.WriteDictionary(ValueConverter, options, ref current, writer);
- }
-
public override void WriteEnumerable(JsonSerializerOptions options, ref WriteStackFrame current, Utf8JsonWriter writer)
{
if (ValueConverter != null)
}
IEnumerable value = ReadStackFrame.GetEnumerableValue(state.Current);
- if (value == null)
- {
- // We added the items to the list property already.
- state.Current.ResetProperty();
- return false;
- }
-
bool setPropertyDirectly;
+ bool popStackOnEnd = state.Current.PopStackOnEnd;
+
if (state.Current.TempEnumerableValues != null)
{
JsonEnumerableConverter converter = state.Current.JsonPropertyInfo.EnumerableConverter;
value = converter.CreateFromList(elementType, (IList)value);
setPropertyDirectly = true;
}
+ else if (!popStackOnEnd)
+ {
+ Debug.Assert(state.Current.IsPropertyEnumerable);
+
+ // We added the items to the list property already.
+ state.Current.ResetProperty();
+ return false;
+ }
else
{
setPropertyDirectly = false;
}
- bool valueReturning = state.Current.PopStackOnEnd;
- if (state.Current.PopStackOnEnd)
+ if (popStackOnEnd)
{
state.Pop();
}
ApplyObjectToEnumerable(value, options, ref state, ref reader, setPropertyDirectly: setPropertyDirectly);
- if (!valueReturning)
+ if (!popStackOnEnd)
{
+ Debug.Assert(state.Current.IsPropertyEnumerable);
state.Current.ResetProperty();
}
}
else
{
- ((IList)state.Current.JsonPropertyInfo.GetValueAsObject(state.Current.ReturnValue)).Add(value);
+ IList list = (IList)state.Current.JsonPropertyInfo.GetValueAsObject(state.Current.ReturnValue);
+ Debug.Assert(list != null);
+ list.Add(value);
}
}
else if (state.Current.IsDictionary)
}
else
{
- ((IList<TProperty>)state.Current.JsonPropertyInfo.GetValueAsObject(state.Current.ReturnValue)).Add(value);
+ IList<TProperty> list = (IList<TProperty>)state.Current.JsonPropertyInfo.GetValueAsObject(state.Current.ReturnValue);
+ Debug.Assert(list != null);
+ list.Add(value);
}
}
else if (state.Current.IsDictionary)
if (state.Current.IsPropertyEnumerable)
{
- state.Current.JsonPropertyInfo.ApplyNullValue(options, ref state, ref reader);
+ bool setPropertyToNull = !state.Current.EnumerableCreated;
+ ApplyObjectToEnumerable(null, options, ref state, ref reader, setPropertyDirectly: setPropertyToNull);
return false;
}
if (state.Current.IsDictionary)
{
// Verify that the Dictionary can be deserialized by having <string> as first generic argument.
- Debug.Assert(state.Current.JsonClassInfo.Type.GetGenericArguments().Length >= 1);
- if (state.Current.JsonClassInfo.Type.GetGenericArguments()[0].UnderlyingSystemType != typeof(string))
+ Type[] args = state.Current.JsonClassInfo.Type.GetGenericArguments();
+ if (args.Length == 0 || args[0].UnderlyingSystemType != typeof(string))
{
ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(state.Current.JsonClassInfo.Type, reader, state.PropertyPath);
}
- ClassType classType = state.Current.JsonClassInfo.ElementClassInfo.ClassType;
-
if (state.Current.ReturnValue == null)
{
// The Dictionary created below will be returned to corresponding Parse() etc method.
}
else
{
- Debug.Assert(classType == ClassType.Object || classType == ClassType.Dictionary);
+ ClassType classType = state.Current.JsonClassInfo.ElementClassInfo.ClassType;
+
+ // Verify that the second parameter is not a value.
+ if (state.Current.JsonClassInfo.ElementClassInfo.ClassType == ClassType.Value)
+ {
+ ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(state.Current.JsonClassInfo.Type, reader, state.PropertyPath);
+ }
- // A nested object or dictionary.
+ // A nested object, dictionary or enumerable.
JsonClassInfo classInfoTemp = state.Current.JsonClassInfo;
state.Push();
state.Current.JsonClassInfo = classInfoTemp.ElementClassInfo;
if (state.Current.Enumerator == null)
{
- IEnumerable enumerable = (IEnumerable)jsonPropertyInfo.GetValueAsObject(state.Current.CurrentValue);
+ // Verify that the Dictionary can be serialized by having <string> as first generic argument.
+ Type[] args = jsonPropertyInfo.RuntimePropertyType.GetGenericArguments();
+ if (args.Length == 0 || args[0].UnderlyingSystemType != typeof(string))
+ {
+ ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(state.Current.JsonClassInfo.Type, state.PropertyPath);
+ }
+ IEnumerable enumerable = (IEnumerable)jsonPropertyInfo.GetValueAsObject(state.Current.CurrentValue);
if (enumerable == null)
{
// Write a null object or enumerable.
if (enumerable == null)
{
- // Write a null object or enumerable.
- state.Current.WriteObjectOrArrayStart(ClassType.Enumerable, writer, writeNull: true);
+ if (!state.Current.JsonPropertyInfo.IgnoreNullValues)
+ {
+ // Write a null object or enumerable.
+ state.Current.WriteObjectOrArrayStart(ClassType.Enumerable, writer, writeNull: true);
+ }
+
return true;
}
Debug.Assert(_index > 0);
Current = _previous[--_index];
}
+
+ // Return a property path in the form of: [FullNameOfType].FirstProperty.SecondProperty.LastProperty
+ public string PropertyPath
+ {
+ get
+ {
+ StringBuilder path = new StringBuilder();
+
+ if (_previous == null || _index == 0)
+ {
+ path.Append($"[{Current.JsonClassInfo.Type.FullName}]");
+ }
+ else
+ {
+ path.Append($"[{_previous[0].JsonClassInfo.Type.FullName}]");
+
+ for (int i = 0; i < _index; i++)
+ {
+ path.Append(GetPropertyName(_previous[i]));
+ }
+ }
+
+ path.Append(GetPropertyName(Current));
+
+ return path.ToString();
+ }
+ }
+
+ private string GetPropertyName(in WriteStackFrame frame)
+ {
+ if (frame.JsonPropertyInfo != null && frame.JsonClassInfo.ClassType == ClassType.Object)
+ {
+ return $".{frame.JsonPropertyInfo.PropertyInfo.Name}";
+ }
+
+ return string.Empty;
+ }
}
}
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
-using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text.Json.Serialization;
}
[MethodImpl(MethodImplOptions.NoInlining)]
- public static void ThrowJsonException_DeserializeCannotBeNull(in Utf8JsonReader reader, string path)
+ public static void ThrowJsonException_DeserializeUnableToConvertValue(Type propertyType, string path)
{
- ThowJsonException(SR.DeserializeCannotBeNull, in reader, path);
+ string message = SR.Format(SR.DeserializeUnableToConvertValue, propertyType.FullName) + $" Path: {path}.";
+ throw new JsonException(message, path, null, null);
}
[MethodImpl(MethodImplOptions.NoInlining)]
- public static void ThrowObjectDisposedException(string name)
+ public static void ThrowJsonException_DeserializeCannotBeNull(in Utf8JsonReader reader, string path)
{
- throw new ObjectDisposedException(name);
+ ThowJsonException(SR.DeserializeCannotBeNull, in reader, path);
}
[MethodImpl(MethodImplOptions.NoInlining)]
Assert.Equal(0, list.Count);
}
+
+ public static IEnumerable<object[]> ReadNullJson
+ {
+ get
+ {
+ yield return new object[] { $"[null, null, null]", true, true, true };
+ yield return new object[] { $"[null, null, {SimpleTestClass.s_json}]", true, true, false };
+ yield return new object[] { $"[null, {SimpleTestClass.s_json}, null]", true, false, true };
+ yield return new object[] { $"[null, {SimpleTestClass.s_json}, {SimpleTestClass.s_json}]", true, false, false };
+ yield return new object[] { $"[{SimpleTestClass.s_json}, {SimpleTestClass.s_json}, {SimpleTestClass.s_json}]", false, false, false };
+ yield return new object[] { $"[{SimpleTestClass.s_json}, {SimpleTestClass.s_json}, null]", false, false, true };
+ yield return new object[] { $"[{SimpleTestClass.s_json}, null, {SimpleTestClass.s_json}]", false, true, false };
+ yield return new object[] { $"[{SimpleTestClass.s_json}, null, null]", false, true, true };
+ }
+ }
+
+ private static void VerifyReadNull(SimpleTestClass obj, bool isNull)
+ {
+ if (isNull)
+ {
+ Assert.Null(obj);
+ }
+ else
+ {
+ obj.Verify();
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(ReadNullJson))]
+ public static void ReadNull(string json, bool element0Null, bool element1Null, bool element2Null)
+ {
+ SimpleTestClass[] arr = JsonSerializer.Parse<SimpleTestClass[]>(json);
+ Assert.Equal(3, arr.Length);
+ VerifyReadNull(arr[0], element0Null);
+ VerifyReadNull(arr[1], element1Null);
+ VerifyReadNull(arr[2], element2Null);
+
+ List<SimpleTestClass> list = JsonSerializer.Parse<List<SimpleTestClass>>(json);
+ Assert.Equal(3, list.Count);
+ VerifyReadNull(list[0], element0Null);
+ VerifyReadNull(list[1], element1Null);
+ VerifyReadNull(list[2], element2Null);
+ }
+
[Fact]
public static void ReadClassWithStringArray()
{
// 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 Xunit;
Assert.Equal(1, obj[longPropertyName]);
}
}
+
+ [Fact]
+ public static void ObjectToStringFail()
+ {
+ string json = @"{""MyDictionary"":{""Key"":""Value""}}";
+ Assert.Throws<JsonException>(() => JsonSerializer.Parse<Dictionary<string, string>>(json));
+ }
+
+ [Fact]
+ public static void HashtableFail()
+ {
+ {
+ string json = @"{""Key"":""Value""}";
+
+ // Verify we can deserialize into Dictionary<,>
+ JsonSerializer.Parse<Dictionary<string, string>>(json);
+
+ // We don't support non-generic IDictionary
+ Assert.Throws<JsonException>(() => JsonSerializer.Parse<Hashtable>(json));
+ }
+
+ {
+ Hashtable ht = new Hashtable();
+ ht.Add("Key", "Value");
+ Assert.Throws<JsonException>(() => JsonSerializer.ToString(ht));
+ }
+
+ {
+ string json = @"{""Key"":""Value""}";
+
+ // We don't support non-generic IDictionary
+ Assert.Throws<JsonException>(() => JsonSerializer.Parse<IDictionary>(json));
+ }
+
+ {
+ IDictionary ht = new Hashtable();
+ ht.Add("Key", "Value");
+ Assert.Throws<JsonException>(() => JsonSerializer.ToString(ht));
+ }
+ }
}
}
TestClassWithInitializedProperties obj = JsonSerializer.Parse<TestClassWithInitializedProperties>(TestClassWithInitializedProperties.s_null_json);
Assert.Equal(null, obj.MyString);
Assert.Equal(null, obj.MyInt);
+ Assert.Equal(null, obj.MyIntArray);
+ Assert.Equal(null, obj.MyIntList);
}
[Fact]
TestClassWithInitializedProperties obj = JsonSerializer.Parse<TestClassWithInitializedProperties>(TestClassWithInitializedProperties.s_null_json, options);
Assert.Equal("Hello", obj.MyString);
Assert.Equal(1, obj.MyInt);
+ Assert.Equal(1, obj.MyIntArray[0]);
+ Assert.Equal(1, obj.MyIntList[0]);
}
[Fact]
var obj = new TestClassWithInitializedProperties();
obj.MyString = null;
obj.MyInt = null;
+ obj.MyIntArray = null;
+ obj.MyIntList = null;
string json = JsonSerializer.ToString(obj);
Assert.Contains(@"""MyString"":null", json);
Assert.Contains(@"""MyInt"":null", json);
+ Assert.Contains(@"""MyIntArray"":null", json);
+ Assert.Contains(@"""MyIntList"":null", json);
}
[Fact]
var obj = new TestClassWithInitializedProperties();
obj.MyString = null;
obj.MyInt = null;
+ obj.MyIntArray = null;
+ obj.MyIntList = null;
string json = JsonSerializer.ToString(obj, options);
Assert.Equal(@"{}", json);
public Dictionary<string, string> MyStringToStringDict { get; set; }
public IDictionary<string, string> MyStringToStringIDict { get; set; }
public IReadOnlyDictionary<string, string> MyStringToStringIReadOnlyDict { get; set; }
+ public List<string> MyListOfNullString { get; set; }
public static readonly string s_json = $"{{{s_partialJsonProperties},{s_partialJsonArrays}}}";
public static readonly string s_json_flipped = $"{{{s_partialJsonArrays},{s_partialJsonProperties}}}";
@"""MyStringIListT"" : [""Hello""]," +
@"""MyStringICollectionT"" : [""Hello""]," +
@"""MyStringIReadOnlyCollectionT"" : [""Hello""]," +
- @"""MyStringIReadOnlyListT"" : [""Hello""]";
+ @"""MyStringIReadOnlyListT"" : [""Hello""]," +
+ @"""MyListOfNullString"" : [null]";
public static readonly byte[] s_data = Encoding.UTF8.GetBytes(s_json);
MyStringToStringDict = new Dictionary<string, string> { { "key", "value" } };
MyStringToStringIDict = new Dictionary<string, string> { { "key", "value" } };
MyStringToStringIReadOnlyDict = new Dictionary<string, string> { { "key", "value" } };
+ MyListOfNullString = new List<string> { null };
}
public void Verify()
Assert.Equal("value", MyStringToStringDict["key"]);
Assert.Equal("value", MyStringToStringIDict["key"]);
Assert.Equal("value", MyStringToStringIReadOnlyDict["key"]);
+ Assert.Null(MyListOfNullString[0]);
}
}
}
public DateTimeOffset?[] MyDateTimeOffsetArray { get; set; }
public SampleEnum?[] MyEnumArray { get; set; }
public Dictionary<string, string> MyStringToStringDict { get; set; }
+ public List<int?> MyListOfNullInt { get; set; }
}
public class SimpleTestClassWithNulls : SimpleBaseClassWithNullables, ITestClass
Assert.Null(MyDateTimeOffsetArray);
Assert.Null(MyEnumArray);
Assert.Null(MyStringToStringDict);
+ Assert.Null(MyListOfNullInt);
}
public static readonly string s_json =
@"{" +
@"""MyDateTimeArray"" : null," +
@"""MyDateTimeOffsetArray"" : null," +
@"""MyEnumArray"" : null," +
- @"""MyStringToStringDict"" : null" +
+ @"""MyStringToStringDict"" : null," +
+ @"""MyListOfNullInt"" : null" +
@"}";
public static readonly byte[] s_data = Encoding.UTF8.GetBytes(s_json);
@"""MyDateTimeArray"" : [""2019-01-30T12:01:02.0000000Z""]," +
@"""MyDateTimeOffsetArray"" : [""2019-01-30T12:01:02.0000000+01:00""]," +
@"""MyEnumArray"" : [2]," +
- @"""MyStringToStringDict"" : {""key"" : ""value""}" +
+ @"""MyStringToStringDict"" : {""key"" : ""value""}," +
+ @"""MyListOfNullInt"" : [null]" +
@"}";
public static readonly byte[] s_data = Encoding.UTF8.GetBytes(s_json);
MyDateTimeOffsetArray = new DateTimeOffset?[] { new DateTimeOffset(2019, 1, 30, 12, 1, 2, new TimeSpan(1, 0, 0)) };
MyEnumArray = new SampleEnum?[] { SampleEnum.Two };
MyStringToStringDict = new Dictionary<string, string> { { "key", "value" } };
+ MyListOfNullInt = new List<int?> { null };
}
public void Verify()
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("value", MyStringToStringDict["key"]);
+ Assert.Null(MyListOfNullInt[0]);
}
}
}
public static readonly byte[] s_data = Encoding.UTF8.GetBytes(s_json);
- public void Initialize()
- {
- MyString = null;
- }
-
public void Verify()
{
Assert.Equal(MyString, null);
{
public string MyString { get; set; } = "Hello";
public int? MyInt { get; set; } = 1;
+ public int[] MyIntArray { get; set; } = new int[] { 1 };
+ public List<int> MyIntList { get; set; } = new List<int> { 1 };
public static readonly string s_null_json =
@"{" +
@"""MyString"" : null," +
- @"""MyInt"" : null" +
+ @"""MyInt"" : null," +
+ @"""MyIntArray"" : null," +
+ @"""MyIntList"" : null" +
@"}";
public static readonly byte[] s_data = Encoding.UTF8.GetBytes(s_null_json);
@"{" +
@"""MyData"":[" +
SimpleTestClass.s_json + "," +
+ "null," +
SimpleTestClass.s_json +
@"]" +
@"}");
MyData.Add(obj);
}
+ MyData.Add(null);
+
{
SimpleTestClass obj = new SimpleTestClass();
obj.Initialize();
public void Verify()
{
- Assert.Equal(2, MyData.Count);
+ Assert.Equal(3, MyData.Count);
MyData[0].Verify();
- MyData[1].Verify();
+ Assert.Null(MyData[1]);
+ MyData[2].Verify();
}
}
// Invalid data
Assert.Throws<JsonException>(() => JsonSerializer.Parse<int[]>(Encoding.UTF8.GetBytes(@"[1,""a""]")));
+ // Invalid data
+ Assert.Throws<JsonException>(() => JsonSerializer.Parse<List<int?>>(Encoding.UTF8.GetBytes(@"[1,""a""]")));
+
// Multidimensional arrays currently not supported
Assert.Throws<JsonException>(() => JsonSerializer.Parse<int[,]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")));
}
Assert.Equal("1", json);
}
+ {
+ int? value = 1;
+ string json = JsonSerializer.ToString(value);
+ Assert.Equal("1", json);
+ }
+
+ {
+ int? value = null;
+ string json = JsonSerializer.ToString(value);
+ Assert.Equal("null", json);
+ }
+
{
Span<byte> json = JsonSerializer.ToBytes(1);
Assert.Equal(Encoding.UTF8.GetBytes("1"), json.ToArray());