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;
[JsonConverter(typeof(AbstractToConcreteConverter<IAmount, Amount>))]
public interface IAmount {
[Newtonsoft.Json.JsonConverter(typeof(NewtonsoftJsonConverter))]
[System.Text.Json.Serialization.JsonConverter(typeof(SystemTextJsonConverter))]
public class Amount : IAmount {
public Amount(decimal value) {
public decimal Value { get; }
public class NewtonsoftJsonConverter : Newtonsoft.Json.JsonConverter {
public override bool CanConvert(Type objectType) => objectType.IsAssignableTo(typeof(IAmount));
public override object? ReadJson(Newtonsoft.Json.JsonReader reader, Type objectType, object? existingValue, Newtonsoft.Json.JsonSerializer serializer) {
throw new NotImplementedException();
public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object? value, Newtonsoft.Json.JsonSerializer serializer) {
writer.WriteRawValue(((IAmount?)value)?.Value.ToString());
public class SystemTextJsonConverter : System.Text.Json.Serialization.JsonConverter<object> {
public override bool CanConvert(Type typeToConvert) => typeToConvert.IsAssignableTo(typeof(IAmount));
public override object Read(ref System.Text.Json.Utf8JsonReader reader, Type typeToConvert, System.Text.Json.JsonSerializerOptions options) =>
new Amount(reader.GetDecimal());
public override void Write(System.Text.Json.Utf8JsonWriter writer, object value, System.Text.Json.JsonSerializerOptions options) =>
writer.WriteRawValue(((IAmount)value).Value.ToString());
public class AbstractToConcreteConverter<TAbstract, TConcrete> : JsonConverter<TAbstract> where TConcrete : TAbstract
static AbstractToConcreteConverter()
if (typeof(TAbstract) == typeof(TConcrete))
throw new ArgumentException(string.Format("Identical type {0} used for both TAbstract and TConcrete", typeof(TConcrete)));
public override TAbstract? Read(ref System.Text.Json.Utf8JsonReader reader, Type typeToConvert, System.Text.Json.JsonSerializerOptions options) =>
JsonSerializer.Deserialize<TConcrete>(ref reader, options);
public override void Write(System.Text.Json.Utf8JsonWriter writer, TAbstract value, System.Text.Json.JsonSerializerOptions options) =>
JsonSerializer.Serialize(writer, (TConcrete)value!, options);
public static void Test()
var foo = new Amount(10);
var newtonJson = Newtonsoft.Json.JsonConvert.SerializeObject(foo);
var systemJson = System.Text.Json.JsonSerializer.Serialize<IAmount>(foo);
var foo2 = System.Text.Json.JsonSerializer.Deserialize<IAmount>(systemJson);
Console.WriteLine("Newtonsoft JSON:\n {0}", newtonJson);
Console.WriteLine("System.Text.Json JSON:\n {0}", systemJson);
Assert.AreEqual(newtonJson, systemJson);
Assert.AreEqual(foo2?.Value, foo.Value);
public static void Main()
Console.WriteLine("Environment version: {0} ({1}), {2}", System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription , Environment.Version, Environment.OSVersion);
Console.WriteLine("System.Text.Json version: " + typeof(JsonSerializer).Assembly.FullName);
Console.WriteLine("Failed with unhandled exception: ");