using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Collections.ObjectModel;
using System.Text.Json.Serialization;
[JsonPropertyName("parentname")]
public string ParentName { get; set; }
public Dictionary<string, User> UserTable { get; } = new Dictionary<string, User>();
public IDictionary<string, JsonElement> ExtensionData { get => UserTable.ToExtensionDictionary(); set => throw new NotImplementedException(); }
public string name { get; set; }
public string state { get; set; }
public string id { get; set; }
public static partial class JsonExtensions
public static IDictionary<string, JsonElement> ToExtensionDictionary<TValue>(this IDictionary<string, TValue> dictionary, JsonSerializerOptions options = null)
throw new ArgumentNullException();
return new DictionaryValueAdapter<string, TValue, JsonElement>(dictionary, e => e.ToObject<TValue>(options), v => JsonElementFromObject(v, options));
public static T ToObject<T>(this JsonElement element, JsonSerializerOptions options = null)
var bufferWriter = new ArrayBufferWriter<byte>();
using (var writer = new Utf8JsonWriter(bufferWriter))
return JsonSerializer.Deserialize<T>(bufferWriter.WrittenSpan, options);
public static T ToObject<T>(this JsonDocument document, JsonSerializerOptions options = null)
throw new ArgumentNullException(nameof(document));
return document.RootElement.ToObject<T>(options);
public static JsonDocument JsonDocumentFromObject<T>(T item, JsonSerializerOptions options = null)
var bytes = JsonSerializer.SerializeToUtf8Bytes(item, options);
return JsonDocument.Parse(new ReadOnlyMemory<byte>(bytes));
public static JsonElement JsonElementFromObject<T>(T item, JsonSerializerOptions options = null)
using var doc = JsonDocumentFromObject(item, options);
return doc.RootElement.Clone();
public class DictionaryValueAdapter<TKey, TValueIn, TValueOut> : IDictionary<TKey, TValueOut>, IDictionary
public IDictionary<TKey, TValueIn> Dictionary { get; }
readonly Func<TValueOut, TValueIn> toInner;
readonly Func<TValueIn, TValueOut> toOuter;
public DictionaryValueAdapter(IDictionary<TKey, TValueIn> dictionary, Func<TValueOut, TValueIn> toInner, Func<TValueIn, TValueOut> toOuter)
this.Dictionary = dictionary ?? throw new ArgumentNullException(nameof(dictionary));
this.toInner = toInner ?? throw new ArgumentNullException(nameof(toInner));
this.toOuter = toOuter ?? throw new ArgumentNullException(nameof(toOuter));
#region IDictionary<TKey,TValueOut> Members
public bool TryGetValue(TKey key, out TValueOut value)
if (Dictionary.TryGetValue(key, out var inner))
value = default(TValueOut);
public void Add(TKey key, TValueOut value) => Dictionary.Add(key, toInner(value));
public bool ContainsKey(TKey key) => Dictionary.ContainsKey(key);
public ICollection<TKey> Keys => Dictionary.Keys;
public bool Remove(TKey key) => Dictionary.Remove(key);
public TValueOut this[TKey key] { get => toOuter(Dictionary[key]); set => Dictionary[key] = toInner(value); }
public ICollection<TValueOut> Values => throw new NotImplementedException();
#region ICollection<KeyValuePair<TKey,TValueOut>> Members
public void Add(KeyValuePair<TKey, TValueOut> item) => Dictionary.Add(new KeyValuePair<TKey, TValueIn>(item.Key, toInner(item.Value)));
public void Clear() => Dictionary.Clear();
public bool Contains(KeyValuePair<TKey, TValueOut> item) => Dictionary.Contains(new KeyValuePair<TKey, TValueIn>(item.Key, toInner(item.Value)));
public int Count => Dictionary.Count;
public bool IsReadOnly => Dictionary.IsReadOnly;
public bool Remove(KeyValuePair<TKey, TValueOut> item) => Dictionary.Remove(new KeyValuePair<TKey, TValueIn>(item.Key, toInner(item.Value)));
public void CopyTo(KeyValuePair<TKey, TValueOut>[] array, int arrayIndex) => throw new NotImplementedException();
#region IEnumerable<KeyValuePair<TKey,TValueOut>> Members
public IEnumerator<KeyValuePair<TKey, TValueOut>> GetEnumerator() => Dictionary.Select(p => new KeyValuePair<TKey, TValueOut>(p.Key, toOuter(p.Value))).GetEnumerator();
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => GetEnumerator();
#region IDictionary Members
void IDictionary.Add(object key, object value) => Add((TKey)key, (TValueOut)value);
bool IDictionary.Contains(object key) => ContainsKey((TKey)key);
object IDictionary.this[object key] { get => this[(TKey)key]; set => this[(TKey)key] = (TValueOut)value; }
IDictionaryEnumerator IDictionary.GetEnumerator() => new DictionaryEnumerator<TKey, TValueOut>(this.GetEnumerator());
void IDictionary.Remove(object key) => Remove((TKey)key);
bool IDictionary.IsFixedSize => false;
ICollection IDictionary.Keys => throw new NotImplementedException();
ICollection IDictionary.Values => throw new NotImplementedException();
#region ICollection Members
void ICollection.CopyTo(Array array, int index) => throw new NotImplementedException();
bool ICollection.IsSynchronized => false;
object ICollection.SyncRoot => throw new NotImplementedException();
public class DictionaryEnumerator<TKey, TValue> : IDictionaryEnumerator
public DictionaryEnumerator(IEnumerator<KeyValuePair<TKey, TValue>> enumerator) => this.Enumerator = enumerator ?? throw new ArgumentNullException();
readonly IEnumerator<KeyValuePair<TKey, TValue>> Enumerator;
public DictionaryEntry Entry => new DictionaryEntry(Enumerator.Current.Key, Enumerator.Current.Value);
public object Key => Enumerator.Current.Key;
public object Value => Enumerator.Current.Value;
public object Current => Entry;
public bool MoveNext() => Enumerator.MoveNext();
public void Reset() => Enumerator.Reset();
public static void Test()
var options = new JsonSerializerOptions { WriteIndented = true };
var users1 = JsonSerializer.Deserialize<Users>(json, options);
Assert.AreEqual(3, users1.UserTable.Count);
var json2 = JsonSerializer.Serialize(users1, options);
Console.WriteLine(json2);
Assert.IsTrue(Newtonsoft.Json.Linq.JToken.DeepEquals(Newtonsoft.Json.Linq.JToken.Parse(json), Newtonsoft.Json.Linq.JToken.Parse(json2)), "JToken.DeepEquals");
var users2 = JsonSerializer.Deserialize<Users>(json2, options);
users2.UserTable.Add("Foo User", new User { name = "foo name" });
var json3 = JsonSerializer.Serialize(users2, options);
var users3 = JsonSerializer.Deserialize<Users>(json3, options);
Assert.AreEqual(4, users3.UserTable.Count);
var json4 = JsonSerializer.Serialize(users3, options);
Console.WriteLine(json4);
Assert.AreEqual(json3, json4);
Assert.IsTrue(users1.UserTable.Keys.SequenceEqual(users3.UserTable.Keys.Take(users1.UserTable.Keys.Count)));
Assert.IsTrue(users1.UserTable.Values.Select(v => v.name).SequenceEqual(users3.UserTable.Values.Select(v => v.name).Take(users1.UserTable.Keys.Count)));
""id"" : ""cedf-c56f-18a4-4b1""
""id"" : ""ebb2-92bf-3062-7774""
""id"" : ""fb60-b34f-6dc8-aaf7""
public static void Main()
Console.WriteLine("Environment version: {0} ({1})", System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription , GetNetCoreVersion());
Console.WriteLine(string.Format("{0} version: {1}", typeof(JsonSerializer).Namespace, typeof(JsonSerializer).Assembly.FullName));
Console.WriteLine("Failed with unhandled exception: ");
public static string GetNetCoreVersion()
var assembly = typeof(System.Runtime.GCSettings).GetTypeInfo().Assembly;
var assemblyPath = assembly.CodeBase.Split(new[] { '/', '\\' }, StringSplitOptions.RemoveEmptyEntries);
int netCoreAppIndex = Array.IndexOf(assemblyPath, "Microsoft.NETCore.App");
if (netCoreAppIndex > 0 && netCoreAppIndex < assemblyPath.Length - 2)
return assemblyPath[netCoreAppIndex + 1];