即使使用默认设置,Json.NET也会将枚举序列化为字符串

我正在使用Json.NET 7.0.1。

文档说明了这一点

Enum [序列化为]整数(可以是StringEnumConverter的枚举值名称)

在我的Global.asax.cs中,我指定默认设置如下:

 JsonConvert.DefaultSettings = (() => { var settings = new JsonSerializerSettings(); settings.Converters.Add(new StringEnumConverter()); return settings; }); 

但是,在某些情况下,我希望将Enums序列化为整数,例如当我构建要存储在数据库中的JSON时。

我是这样做的:

 public class JsonSerializedType : IUserType where T : class { private static readonly JsonSerializerSettings serializerSettings = new JsonSerializerSettings(); public void NullSafeSet(IDbCommand cmd, object value, int index) { cmd.Parameters[index].Value = JsonConvert.SerializeObject(value as T, serializerSettings); } } 

但是,即使在这种情况下, Enums也会被序列化为字符串。 我检查了serializerSettings没有Converters ,它的ContractResolvernull

为什么会这样?

发生这种情况是因为JsonConvert.SerializeObject通过内部调用JsonSerializer.CreateDefault(JsonSerializerSettings settings)将传入设置应用于默认设置 JsonSerializer.CreateDefault(JsonSerializerSettings settings) 。 我不知道是否/在哪里记录了这种行为,但它在源代码中可见。 因此,除了本地指定的转换器的空列表之外,还将使用默认的转换器列表,这意味着将使用默认的StringEnumConverter

您有几个选项可以解决此问题:

  1. 不使用默认设置自己构造JsonSerializer

     public static class JsonExtensions { public static string SerializeObjectNoDefaultSettings(object value, Formatting formatting, JsonSerializerSettings settings) { var jsonSerializer = JsonSerializer.Create(settings); jsonSerializer.Formatting = formatting; StringBuilder sb = new StringBuilder(256); StringWriter sw = new StringWriter(sb, CultureInfo.InvariantCulture); using (JsonTextWriter jsonWriter = new JsonTextWriter(sw)) { jsonWriter.Formatting = jsonSerializer.Formatting; jsonSerializer.Serialize(jsonWriter, value); } return sw.ToString(); } } 

    然后使用它像:

     var json = JsonExtensions.SerializeObjectNoDefaultSettings(value, Formatting.None, new JsonSerializerSettings()); 
  2. 将默认的StringEnumConverter将枚举序列化为字符串的StringEnumConverter ,例如:

     public class IntegerEnumConverter : StringEnumConverter { public override bool CanRead { get { return false; } } public override bool CanWrite { get { return false; } } } 

    然后使用它像:

     var json = JsonConvert.SerializeObject(value, Formatting.None, new JsonSerializerSettings { Converters = new JsonConverter[] { new IntegerEnumConverter() } }); 

    将优先选择本地指定的转换器,而不是默认转换器。

暂时JsonConvert.DefaultSettings将是一个坏主意,因为它不是线程安全的。

原因

我们在这里看到的行为是设计的, JsonConvert方法中的传递设置正在与提供的DefaultSettings合并,这里是来自JsonSerializer类的Json.Net源代码的一小部分,以揭开情境的神秘面纱。

  private static void ApplySerializerSettings(JsonSerializer serializer, JsonSerializerSettings settings) { if (!CollectionUtils.IsNullOrEmpty(settings.Converters)) { // insert settings converters at the beginning so they take precedence // if user wants to remove one of the default converters they will have to do it manually for (int i = 0; i < settings.Converters.Count; i++) { serializer.Converters.Insert(i, settings.Converters[i]); } } 

我们可以看到转换器与提供的默认转换器合并,虽然具有更高的优先级。

我们可以利用最近合并的转换器的更高优先级并阻止StringEnumConverter转换。

 class PreventStringEnumConverter : StringEnumConverter { public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { var type = value.GetType(); var undertype = Enum.GetUnderlyingType(type); var converted=Convert.ChangeType(value, undertype); writer.WriteValue(converted); } } 

用法如下:

 var json = JsonConvert.SerializeObject(obj, new JsonSerializerSettings { Converters = new List {new PreventStringEnumConverter()} });