Json.net反序列化空GUID情况

14

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

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

但是反序列化需要访问私有字段,因为当我尝试反序列化时会出现以下错误:

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

我该如何使它忽略私有字段并改用公共属性呢?

1个回答

29
Json.NET 拒绝为 Guid 设置 null 值,因为它是一个非可空值类型。在 Immediate Window 中尝试输入 (Guid)null,您将看到一个错误消息,指示在 .Net 中无法进行此转换。
要解决此问题,您有几个选择:
  1. Create a Guid? nullable proxy property. It can be private if you desire as long as it has a [JsonProperty] attribute:

    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. Create a JsonConverter that converts a null Json token to a default Guid value:

    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);
        }
    }
    

    Then apply it to your type as follows:

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

    Alternatively, you can apply the converter to all values of type T by adding the converter to JsonSerializerSettings.Converters. And, to register such a converter globally, see e.g.How to set custom JsonSerializerSettings for Json.NET in MVC 4 Web API? for Web API, Setting JsonConvert.DefaultSettings asp net core 2.0 not working as expected for ASP.NET Core or Registering a custom JsonConverter globally in Json.Net for a console app.

    If you do register the converter globally for a console app, you may need to disable it for recursive calls as shown in JSON.Net throws StackOverflowException when using [JsonConvert()].

  3. If you only need to deserialize a null value for a Guid and not re-serialize it as such, you can apply [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] to the Guid property, and null values will ignored despite being invalid Guid values:

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

    Of course if you do this your Guid will be re-serialized as "00000000-0000-0000-0000-000000000000". To ameliorate that you could apply DefaultValueHandling = DefaultValueHandling.Ignore which will cause empty Guid values to be omitted during serialization:

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

    Note that if a parameterized constructor called during deserialization has a non-nullable Guid argument with the same name, a different approach may be required.


谢谢!有一个关于Null转默认值转换器的问题。我是否需要手动为类中的每个字段/属性添加JsonConverter属性,还是可以以某种方式为类中的所有属性添加它? - Adrian Buzea
1
你可以将其添加到每个属性中,或者在所有类中全局注册以供使用。请参阅在Json.Net中注册自定义JsonConverter - dbc
第三个选项正是我所需要的。感谢您提供了广泛的答案以供可能的使用情况。 - Efreeto

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接