if (!(typeof(IEnumerable).IsAssignableFrom(queryType)) ||
queryType == typeof(string) ||
- queryType.IsAbstract ||
queryType.IsInterface ||
queryType.IsArray ||
IsNativelySupportedCollection(queryType))
}
}
- // Try non-generic interfaces without add methods
- if (typeof(IEnumerable).IsAssignableFrom(queryType))
- {
- return typeof(IEnumerable);
- }
- else if (typeof(ICollection).IsAssignableFrom(queryType))
- {
- return typeof(ICollection);
- }
-
- // No natively supported collection that we support as derived types was detected.
- return queryType;
+ return typeof(IEnumerable);
}
public static bool IsDeserializedByAssigningFromList(Type type)
}
else if (ClassType == ClassType.Enumerable)
{
- // Else if it's an implementing type that is not assignable from IList.
+ // Else if it's an implementing type whose runtime type is not assignable to IList.
if (DeclaredPropertyType != ImplementedPropertyType &&
- (!typeof(IList).IsAssignableFrom(DeclaredPropertyType) ||
+ (!typeof(IList).IsAssignableFrom(RuntimePropertyType) ||
ImplementedPropertyType == typeof(ArrayList) ||
ImplementedPropertyType == typeof(IList)))
{
public override IEnumerable CreateDerivedEnumerableInstance(JsonPropertyInfo collectionPropertyInfo, IList sourceList, string jsonPath, JsonSerializerOptions options)
{
+ // Implementing types that don't have default constructors are not supported for deserialization.
+ if (collectionPropertyInfo.DeclaredTypeClassInfo.CreateObject == null)
+ {
+ throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection(
+ collectionPropertyInfo.DeclaredPropertyType,
+ collectionPropertyInfo.ParentClassType,
+ collectionPropertyInfo.PropertyInfo);
+ }
+
object instance = collectionPropertyInfo.DeclaredTypeClassInfo.CreateObject();
if (instance is IList instanceOfIList)
return instanceOfQueue;
}
- // TODO: Use reflection to support types implementing Stack or Queue.
+ // TODO (https://github.com/dotnet/corefx/issues/40479):
+ // Use reflection to support types implementing Stack or Queue.
throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection(
collectionPropertyInfo.DeclaredPropertyType,
public override object CreateDerivedDictionaryInstance(JsonPropertyInfo collectionPropertyInfo, IDictionary sourceDictionary, string jsonPath, JsonSerializerOptions options)
{
+ // Implementing types that don't have default constructors are not supported for deserialization.
+ if (collectionPropertyInfo.DeclaredTypeClassInfo.CreateObject == null)
+ {
+ throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection(
+ collectionPropertyInfo.DeclaredPropertyType,
+ collectionPropertyInfo.ParentClassType,
+ collectionPropertyInfo.PropertyInfo);
+ }
+
object instance = collectionPropertyInfo.DeclaredTypeClassInfo.CreateObject();
if (instance is IDictionary instanceOfIDictionary)
}
}
- // TODO: Use reflection to support types implementing SortedList and maybe immutable dictionaries.
+ // TODO (https://github.com/dotnet/corefx/issues/40479):
+ // Use reflection to support types implementing SortedList and maybe immutable dictionaries.
// Types implementing SortedList and immutable dictionaries will fail here.
throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection(
--- /dev/null
+// 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.ObjectModel;
+using Xunit;
+
+namespace System.Text.Json.Serialization.Tests
+{
+ public static partial class ValueTests
+ {
+ [Fact]
+ public static void Read_ObjectModelCollection()
+ {
+ Collection<bool> c = JsonSerializer.Deserialize<Collection<bool>>("[true,false]");
+ Assert.Equal(2, c.Count);
+ Assert.True(c[0]);
+ Assert.False(c[1]);
+
+ // Regression test for https://github.com/dotnet/corefx/issues/40597.
+ ObservableCollection<bool> oc = JsonSerializer.Deserialize<ObservableCollection<bool>>("[true,false]");
+ Assert.Equal(2, oc.Count);
+ Assert.True(oc[0]);
+ Assert.False(oc[1]);
+
+ SimpleKeyedCollection kc = JsonSerializer.Deserialize<SimpleKeyedCollection>("[true]");
+ Assert.Equal(1, kc.Count);
+ Assert.True(kc[0]);
+ }
+
+ [Fact]
+ public static void Read_ObjectModelCollection_Throws()
+ {
+ // No default constructor.
+ Assert.Throws<NotSupportedException>(() => JsonSerializer.Deserialize<ReadOnlyCollection<bool>>("[true,false]"));
+ // No default constructor.
+ Assert.Throws<NotSupportedException>(() => JsonSerializer.Deserialize<ReadOnlyObservableCollection<bool>>("[true,false]"));
+ // No default constructor.
+ Assert.Throws<NotSupportedException>(() => JsonSerializer.Deserialize<ReadOnlyDictionary<string, bool>>(@"{""true"":false}"));
+
+ // Abstract types can't be instantiated. This means there's no default constructor, so the type is not supported for deserialization.
+ Assert.Throws<NotSupportedException>(() => JsonSerializer.Deserialize<KeyedCollection<string, bool>>("[true]"));
+ }
+
+ public class SimpleKeyedCollection : KeyedCollection<string, bool>
+ {
+ protected override string GetKeyForItem(bool item)
+ {
+ return item.ToString();
+ }
+ }
+ }
+}
--- /dev/null
+// 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.Collections.ObjectModel;
+using Xunit;
+
+namespace System.Text.Json.Serialization.Tests
+{
+ public static partial class ValueTests
+ {
+ [Fact]
+ public static void Write_ObjectModelCollection()
+ {
+ Collection<bool> c = new Collection<bool>() { true, false };
+ Assert.Equal("[true,false]", JsonSerializer.Serialize(c));
+
+ ObservableCollection<bool> oc = new ObservableCollection<bool>() { true, false };
+ Assert.Equal("[true,false]", JsonSerializer.Serialize(oc));
+
+ SimpleKeyedCollection kc = new SimpleKeyedCollection() { true, false };
+ Assert.Equal("[true,false]", JsonSerializer.Serialize(kc));
+ Assert.Equal("[true,false]", JsonSerializer.Serialize<KeyedCollection<string, bool>>(kc));
+
+ ReadOnlyCollection<bool> roc = new ReadOnlyCollection<bool>(new List<bool> { true, false });
+ Assert.Equal("[true,false]", JsonSerializer.Serialize(oc));
+
+ ReadOnlyObservableCollection<bool> rooc = new ReadOnlyObservableCollection<bool>(oc);
+ Assert.Equal("[true,false]", JsonSerializer.Serialize(rooc));
+
+ ReadOnlyDictionary<string, bool> rod = new ReadOnlyDictionary<string, bool>(new Dictionary<string, bool> { ["true"] = false } );
+ Assert.Equal(@"{""true"":false}", JsonSerializer.Serialize(rod));
+ }
+ }
+}
<Compile Include="Serialization\Value.ReadTests.GenericCollections.cs" />
<Compile Include="Serialization\Value.ReadTests.ImmutableCollections.cs" />
<Compile Include="Serialization\Value.ReadTests.NonGenericCollections.cs" />
+ <Compile Include="Serialization\Value.ReadTests.ObjectModelCollections.cs" />
<Compile Include="Serialization\Value.WriteTests.cs" />
<Compile Include="Serialization\Value.WriteTests.GenericCollections.cs" />
<Compile Include="Serialization\Value.WriteTests.ImmutableCollections.cs" />
<Compile Include="Serialization\Value.WriteTests.NonGenericCollections.cs" />
+ <Compile Include="Serialization\Value.WriteTests.ObjectModelCollections.cs" />
<Compile Include="Serialization\WriteValueTests.cs" />
<Compile Include="TestCaseType.cs" />
<Compile Include="TestClasses.ClassWithComplexObjects.cs" />