jsonPropertyInfo.DeclaredPropertyType.GetGenericArguments()[1].UnderlyingSystemType == typeof(object) ||
jsonPropertyInfo.DeclaredPropertyType.GetGenericArguments()[1].UnderlyingSystemType == typeof(JsonElement));
- Debug.Assert(jsonPropertyInfo.RuntimeClassInfo.CreateObject != null);
+ if (jsonPropertyInfo.RuntimeClassInfo.CreateObject == null)
+ {
+ ThrowHelper.ThrowNotSupportedException_SerializationNotSupported(jsonPropertyInfo.DeclaredPropertyType);
+ }
+
extensionData = (IDictionary?)jsonPropertyInfo.RuntimeClassInfo.CreateObject();
jsonPropertyInfo.SetValueAsObject(obj, extensionData);
}
using System.Collections;
using System.Collections.Generic;
+using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using Xunit;
}
[Fact]
+ public static void DeserializeIntoImmutableDictionaryProperty()
+ {
+ // baseline
+ JsonSerializer.Deserialize<ClassWithExtensionPropertyAsImmutable>(@"{}");
+ JsonSerializer.Deserialize<ClassWithExtensionPropertyAsImmutableJsonElement>(@"{}");
+ JsonSerializer.Deserialize<ClassWithExtensionPropertyPrivateConstructor>(@"{}");
+ JsonSerializer.Deserialize<ClassWithExtensionPropertyPrivateConstructorJsonElement>(@"{}");
+
+ Assert.Throws<NotSupportedException>(() => JsonSerializer.Deserialize<ClassWithExtensionPropertyAsImmutable>("{\"hello\":\"world\"}"));
+ Assert.Throws<NotSupportedException>(() => JsonSerializer.Deserialize<ClassWithExtensionPropertyAsImmutableJsonElement>("{\"hello\":\"world\"}"));
+ Assert.Throws<NotSupportedException>(() => JsonSerializer.Deserialize<ClassWithExtensionPropertyPrivateConstructor>("{\"hello\":\"world\"}"));
+ Assert.Throws<NotSupportedException>(() => JsonSerializer.Deserialize<ClassWithExtensionPropertyPrivateConstructorJsonElement>("{\"hello\":\"world\"}"));
+ Assert.Throws<InvalidOperationException>(() => JsonSerializer.Deserialize<ClassWithExtensionPropertyCustomIImmutable>("{\"hello\":\"world\"}"));
+ Assert.Throws<InvalidOperationException>(() => JsonSerializer.Deserialize<ClassWithExtensionPropertyCustomIImmutableJsonElement>("{\"hello\":\"world\"}"));
+ }
+
+ [Fact]
+ public static void SerializeIntoImmutableDictionaryProperty()
+ {
+ // attempt to serialize a null immutable dictionary
+ string expectedJson = "{}";
+ var obj = new ClassWithExtensionPropertyAsImmutable();
+ var json = JsonSerializer.Serialize(obj);
+ Assert.Equal(expectedJson, json);
+
+ // attempt to serialize an empty immutable dictionary
+ expectedJson = "{}";
+ obj = new ClassWithExtensionPropertyAsImmutable();
+ obj.MyOverflow = ImmutableDictionary<string, object>.Empty;
+ json = JsonSerializer.Serialize(obj);
+ Assert.Equal(expectedJson, json);
+
+ // attempt to serialize a populated immutable dictionary
+ expectedJson = "{\"hello\":\"world\"}";
+ obj = new ClassWithExtensionPropertyAsImmutable();
+ var dictionaryStringObject = new Dictionary<string, object> { { "hello", "world" } };
+ obj.MyOverflow = ImmutableDictionary.CreateRange(dictionaryStringObject);
+ json = JsonSerializer.Serialize(obj);
+ Assert.Equal(expectedJson, json);
+ }
+
+ private class ClassWithExtensionPropertyAsImmutable
+ {
+ [JsonExtensionData]
+ public ImmutableDictionary<string, object> MyOverflow { get; set; }
+ }
+
+ private class ClassWithExtensionPropertyAsImmutableJsonElement
+ {
+ [JsonExtensionData]
+ public ImmutableDictionary<string, JsonElement> MyOverflow { get; set; }
+ }
+
+ private class ClassWithExtensionPropertyPrivateConstructor
+ {
+ [JsonExtensionData]
+ public GenericIDictionaryWrapperPrivateConstructor<string, object> MyOverflow { get; set; }
+ }
+
+ private class ClassWithExtensionPropertyPrivateConstructorJsonElement
+ {
+ [JsonExtensionData]
+ public GenericIDictionaryWrapperPrivateConstructor<string, JsonElement> MyOverflow { get; set; }
+ }
+
+ private class ClassWithExtensionPropertyCustomIImmutable
+ {
+ [JsonExtensionData]
+ public GenericIImmutableDictionaryWrapper<string, object> MyOverflow { get; set; }
+ }
+
+ private class ClassWithExtensionPropertyCustomIImmutableJsonElement
+ {
+ [JsonExtensionData]
+ public GenericIImmutableDictionaryWrapper<string, JsonElement> MyOverflow { get; set; }
+ }
+
+
+ [Fact]
public static void CustomObjectConverterInExtensionProperty()
{
const string Json = "{\"hello\": \"world\"}";
}
}
+ public class GenericIDictionaryWrapperPrivateConstructor<TKey, TValue> : GenericIDictionaryWrapper<TKey, TValue>
+ {
+ private GenericIDictionaryWrapperPrivateConstructor() { }
+ }
+
public class ReadOnlyStringToStringIDictionaryWrapper : StringToStringIDictionaryWrapper
{
public override bool IsReadOnly => true;
}
}
+ public class GenericIImmutableDictionaryWrapper<TKey, TValue> : IImmutableDictionary<TKey, TValue>
+ {
+ private ImmutableDictionary<TKey, TValue> _dictionary;
+
+ public GenericIImmutableDictionaryWrapper() { }
+
+ public GenericIImmutableDictionaryWrapper(Dictionary<TKey, TValue> items)
+ {
+ _dictionary = ImmutableDictionary.CreateRange(items);
+ }
+
+ public TValue this[TKey key] => _dictionary[key];
+
+ public IEnumerable<TKey> Keys => _dictionary.Keys;
+
+ public IEnumerable<TValue> Values => _dictionary.Values;
+
+ public int Count => _dictionary.Count;
+
+ public IImmutableDictionary<TKey, TValue> Add(TKey key, TValue value)
+ {
+ return ((IImmutableDictionary<TKey, TValue>)_dictionary).Add(key, value);
+ }
+
+ public IImmutableDictionary<TKey, TValue> AddRange(IEnumerable<KeyValuePair<TKey, TValue>> pairs)
+ {
+ return ((IImmutableDictionary<TKey, TValue>)_dictionary).AddRange(pairs);
+ }
+
+ public IImmutableDictionary<TKey, TValue> Clear()
+ {
+ return ((IImmutableDictionary<TKey, TValue>)_dictionary).Clear();
+ }
+
+ public bool Contains(KeyValuePair<TKey, TValue> pair)
+ {
+ return _dictionary.Contains(pair);
+ }
+
+ public bool ContainsKey(TKey key)
+ {
+ return _dictionary.ContainsKey(key);
+ }
+
+ public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
+ {
+ return ((IImmutableDictionary<TKey, TValue>)_dictionary).GetEnumerator();
+ }
+
+ public IImmutableDictionary<TKey, TValue> Remove(TKey key)
+ {
+ return ((IImmutableDictionary<TKey, TValue>)_dictionary).Remove(key);
+ }
+
+ public IImmutableDictionary<TKey, TValue> RemoveRange(IEnumerable<TKey> keys)
+ {
+ return ((IImmutableDictionary<TKey, TValue>)_dictionary).RemoveRange(keys);
+ }
+
+ public IImmutableDictionary<TKey, TValue> SetItem(TKey key, TValue value)
+ {
+ return ((IImmutableDictionary<TKey, TValue>)_dictionary).SetItem(key, value);
+ }
+
+ public IImmutableDictionary<TKey, TValue> SetItems(IEnumerable<KeyValuePair<TKey, TValue>> items)
+ {
+ return ((IImmutableDictionary<TKey, TValue>)_dictionary).SetItems(items);
+ }
+
+ public bool TryGetKey(TKey equalKey, out TKey actualKey)
+ {
+ return _dictionary.TryGetKey(equalKey, out actualKey);
+ }
+
+ public bool TryGetValue(TKey key, out TValue value)
+ {
+ return _dictionary.TryGetValue(key, out value);
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return ((IImmutableDictionary<TKey, TValue>)_dictionary).GetEnumerator();
+ }
+ }
+
public class StringIImmutableListWrapper : IImmutableList<string>
{
private ImmutableList<string> _list = ImmutableList.Create<string>();