【问题标题】:Json.net deserialization null guid caseJson.net 反序列化 null guid 案例
【发布时间】:2015-10-23 05:22:19
【问题描述】:

我正在使用 Json.NET 反序列化一个对象,该对象包含 Guid 类型的私有字段和该字段的公共属性。当我的 Guid 的值在我的 json 中为 null 时,我想将 Guid.Empty 分配给我的字段。

public class MyClass
{
    private Guid property;
    public Guid Property
    {
        get { return property; }
        set 
        {
            if (value == null)
            {
                property = Guid.Empty;
            }
            else
            {
                property = value;
            }
        }
    }
}

deserializer 想要访问私有字段,导致我在尝试反序列化时收到此错误:

将值 {null} 转换为类型“System.Guid”时出错。小路 '[0].property',第 6 行,第 26 位。

如何让它忽略私有字段而使用公共属性?

【问题讨论】:

    标签: c# json serialization json.net


    【解决方案1】:

    Json.NET 拒绝为 Guid 设置 null 值,因为它是不可为空的值类型。尝试在Immediate Window 中输入(Guid)null,您将看到一条错误消息,指出无法在.Net 中进行此转换。

    要解决此问题,您有几个选择:

    1. 创建一个Guid? 可为空的代理属性。如果您愿意,它可以是私有的,只要它具有 [JsonProperty] 属性即可:

      public class MyClass
      {
          [JsonIgnore]
          public Guid Property { get; set; }
      
          [JsonProperty("Property")]
          Guid? NullableProperty { get { return Property == Guid.Empty ? null : (Guid?)Property; } set { Property = (value == null ? Guid.Empty : value.Value); } }
      }
      
    2. 创建一个JsonConverter,将null Json 令牌转换为默认的 Guid 值:

      public class NullToDefaultConverter<T> : JsonConverter where T : struct
      {
          public override bool CanConvert(Type objectType)
          {
              return objectType == typeof(T);
          }
      
          public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
          {
              var token = JToken.Load(reader);
              if (token == null || token.Type == JTokenType.Null)
                  return default(T);
              return token.ToObject(objectType); // Deserialize using default serializer
          }
      
          // Return false instead if you don't want default values to be written as null
          public override bool CanWrite { get { return true; } }
      
          public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
          {
              if (EqualityComparer<T>.Default.Equals((T)value, default(T)))
                  writer.WriteNull();
              else
                  writer.WriteValue(value);
          }
      }
      

      然后将其应用于您的类型,如下所示:

      public class MyClass
      {
          [JsonConverter(typeof(NullToDefaultConverter<Guid>))]
          public Guid Property { get; set; }
      }
      

      或者,您可以通过将转换器添加到JsonSerializerSettings.Converters 来将转换器应用于T 类型的所有值。并且,要在全球范围内注册这样的转换器,请参阅例如How to set custom JsonSerializerSettings for Json.NET in MVC 4 Web API? 用于 Web API,Setting JsonConvert.DefaultSettings asp net core 2.0 not working as expected 用于 ASP.NET Core 或 Registering a custom JsonConverter globally in Json.Net 对于控制台应用程序。

      如果您确实为控制台应用程序全局注册了转换器,您可能需要禁用它以进行递归调用,如 JSON.Net throws StackOverflowException when using [JsonConvert()] 所示。

    3. 如果您只需要反序列化 Guid 的 null 值而不是重新序列化它,则可以将 [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] 应用于 Guid 属性,null 值将尽管 Guid 值无效,但仍被忽略:

      public class MyClass
      {
          [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
          public Guid Property { get; set; }
      }
      

      当然,如果您这样做,您的 Guid 将被重新序列化为 "00000000-0000-0000-0000-000000000000"。为了改善这一点,您可以应用DefaultValueHandling = DefaultValueHandling.Ignore,这将导致在序列化过程中省略空的 Guid 值:

      [JsonProperty(NullValueHandling = NullValueHandling.Ignore, DefaultValueHandling = DefaultValueHandling.Ignore)]
      public Guid Property { get; set; }
      

      请注意,如果在反序列化期间调用的 parameterized constructor 具有同名的不可为空的 Guid 参数,则可能需要不同的方法。

    【讨论】:

    • 谢谢!关于 Null 到默认转换器的一个问题。我是否必须手动将 JsonConverter 属性添加到我的类中的每个字段/属性,或者我可以以某种方式为类中的所有属性添加它?
    • 您可以将其添加到每个属性中,也可以将其注册以在所有类中全局使用。见Registering a custom JsonConverter in Json.Net
    • 第三个选项正是我所需要的。感谢您为可能的用例提供广泛的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-09-05
    • 1970-01-01
    • 2012-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多