C#中Blazor ChartJs字符串枚举配置的简化方案问询
优化Blazor ChartJs组件的PointStyle配置序列化方案
问题背景
我维护一个Blazor ChartJs组件,在将C#模型序列化为ChartJs所需的JSON配置时,pointStyle这类配置项仅接受circle、cross等固定字符串值。最初通过自定义类模拟字符串枚举来约束取值,但需要在主模型中维护两个关联属性(一个用于强类型约束,一个用于序列化),实现流程繁琐。
优化方案1:使用C#字符串枚举(推荐)
C# 7.3及以上支持为枚举指定字符串值,配合JsonStringEnumConverter可直接实现正确序列化,无需维护冗余属性。
- 定义带字符串映射的枚举:
using System.Text.Json.Serialization; [JsonConverter(typeof(JsonStringEnumConverter))] public enum PointStyle { [JsonPropertyName("circle")] Circle, [JsonPropertyName("cross")] Cross // 按需添加其他样式 }
- 主模型中直接使用该枚举属性:
[JsonPropertyName("pointStyle")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public PointStyle? PointStyle { get; set; }
设置属性时直接用PointStyle = PointStyle.Cross,序列化后会自动生成"pointStyle": "cross"的JSON,无需手动同步字符串字段。
优化方案2:自定义JsonConverter处理原有PointStyle类
若不想改用枚举,可通过自定义JsonConverter直接序列化原PointStyle类,移除主模型中的冗余属性。
- 实现JsonConverter:
public class PointStyleConverter : JsonConverter<PointStyle> { public override PointStyle Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var value = reader.GetString(); return value switch { "circle" => PointStyle.Circle, "cross" => PointStyle.Cross, _ => throw new JsonException($"无效的PointStyle值: {value}") }; } public override void Write(Utf8JsonWriter writer, PointStyle value, JsonSerializerOptions options) { writer.WriteStringValue(value.Value); } }
- 为模型属性添加转换器特性:
[JsonPropertyName("pointStyle")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonConverter(typeof(PointStyleConverter))] public PointStyle? PointStyle { get; set; }
- 可选:全局注册转换器,避免逐个属性添加特性:
var serializerOptions = new JsonSerializerOptions(); serializerOptions.Converters.Add(new PointStyleConverter()); await JSRuntime.InvokeVoidAsync("setup", Config.CanvasId, dotnet_ref, JsonSerializer.Serialize(Config, serializerOptions));
优化方案3:用记录类型简化原PointStyle类
若坚持用类模拟字符串枚举,可改用C#记录类型简化实现,配合上述JsonConverter使用:
public record PointStyle(string Value) { public static readonly PointStyle Circle = new("circle"); public static readonly PointStyle Cross = new("cross"); }
记录类型自带值相等逻辑,代码比原自定义类更简洁。
内容的提问来源于stack exchange,提问作者Enrico
相关产品推荐
相关产品推荐

