skip to Main Content

I am looking to create a custom JSON converter on my C# application. When I instantiate a new class I am unable to leave it generic.

Class:

using System.Text.Json;
using System.Text.Json.Serialization;

public class Converter<T> : JsonConverter<T> where T : Enum
{
    public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        string? data = reader.GetString();
        return data.GetEnum<T>()!;
    }

    public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
    {
        writer.WriteString(value.GetDescription<T>());
    }
}

2

Answers


  1. You should check the already existing JsonStringEnumConverter: https://learn.microsoft.com/en-us/dotnet/api/system.text.json.serialization.jsonstringenumconverter

    x.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());

    Login or Signup to reply.
  2. You should use the factory pattern to manufacture specific converters for each Enum type as you encounter it:

    public class CustomEnumConverter : JsonConverterFactory
    {
        public override bool CanConvert(Type typeToConvert) => typeToConvert.IsEnum; // Add anything additional here such as typeToConvert.IsEnumWithDescription() to check for description attributes.
    
        public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) =>
            (JsonConverter)Activator.CreateInstance(typeof(CustomConverter<>).MakeGenericType(typeToConvert))!;
    
        class CustomConverter<T> : JsonConverter<T> where T : struct, Enum
        {
            public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) =>
                reader.GetString()!.GetEnumValue<T>()!;
    
            public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) =>
                writer.WriteStringValue(value.GetDescription<T>());
        }
    }
    

    A factory converter can be applied directly to properties as well as long as the factory can return a converter for the property’s type, so there is no need to make the inner converter public:

    public class Model
    {
        [JsonConverter(typeof(CustomEnumConverter))]
        public SomeEnum? SomeEnum { get; set; }
    }
    

    In fact, the built-in JsonStringEnumConverter is also implemented via the factory pattern.

    Demo fiddle here.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search