using System.Text.Json.Serialization;
public static void Main()
Console.WriteLine("Hello World");
public abstract class JsonConverterEx<T> : JsonConverter<T>
public delegate void HandleJsonPropertyNameDelegate(Utf8JsonReader reader, string name);
protected T ReadTypeFromJson(Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options, Func<T> handleJsonEndObject, HandleJsonPropertyNameDelegate handleJsonPropertyName)
if (reader.TokenType != JsonTokenType.StartObject)
throw new JsonException("Expected StartObject token");
switch (reader.TokenType)
case JsonTokenType.EndObject:
return handleJsonEndObject();
case JsonTokenType.PropertyName:
var propName = reader.GetString();
handleJsonPropertyName(reader, propName);
catch (InvalidOperationException e)
$"Unexpected type found", e);
throw new JsonException("Expected EndObject token");
internal class ExampleConverter : JsonConverterEx<Message>
public override Message Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
if (reader.TokenType != JsonTokenType.StartObject)
throw new JsonException("Expected StartObject token");
var id = Option<int>.None;
var sentAt = Option<DateTime>.None;
var messageText = Option<string>.None;
return ReadTypeFromJson(reader, typeToConvert, options,
() => new Message(id, sentAt, messageText),
(reader2, propertyName) =>
id = Option<int>.Some(int.Parse(reader2.GetString() ?? string.Empty));
case nameof(Message.SentAt):
sentAt = Option<DateTime>.Some(reader2.GetDateTime());
case nameof(Message.MessageText):
messageText = Option<string>.Some(reader2.GetString()?.ToUpper());
public override void Write(Utf8JsonWriter writer, Message value, JsonSerializerOptions options)
throw new NotImplementedException();
public int Id { get; set; }
public DateTime SentAt { get; set; }
public string MessageText { get; set; }
public Message(int id, DateTime sentAt, string messageText)
MessageText = messageText;
public static Option<T> None => default;
public static Option<T> Some(T value) => new Option<T>(value);
isSome = this.value is { };
public bool IsSome(out T value)