Json.Net 在使用我的 JsonConverter 之前正在自行转换

Json.Net Is converting on its own before using my JsonConverter

在我的 WPF 代码中,我使用 Newtonsoft.Json 将 json 反序列化到我的模型中。首先,我收到一个 Json 字符串 ('json'),然后我将其解析为 'message'。 (我要反序列化的对象包装在 json 字符串中的 "data" 字段中)。

Activity message = JObject.Parse(json)["data"].ToObject<Activity>();

我的 Activity class 使用多个 [Json属性] 属性来生成其字段。其中之一是名为 'ActivityType' 的枚举。

[JsonProperty("type")]
[JsonConverter(typeof(ActivityTypeConverter))]
public ActivityType Type { get; set; }

public enum ActivityType {
    EmailOpen,
    LinkClick,
    Salesforce,
    Unsupported
};

public class ActivityTypeConverter : JsonConverter {

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var rawString = existingValue.ToString().ToLower();
        if (rawString.Contains("click"))
            return ActivityType.LinkClick;
        else if (rawString.Contains("salesforce"))
            return ActivityType.Salesforce;
        else if (rawString.Contains("email_open"))
            return ActivityType.EmailOpen;
        else
        {
            Console.WriteLine("unsupported " + rawString);
            return ActivityType.Unsupported;
        }
    }

    public override bool CanConvert(Type objectType)
    {
        return !objectType.Equals(typeof(ActivityType));
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

奇怪和令人沮丧的是,我知道有 "type":"email_open" 的 json 个对象被反序列化为 ActivityType.Unsupported,即使我的转换器应该反序列化它们作为电子邮件打开。

调试显示问题所在: json 字段 "type" 自动反序列化 "email_open" 作为 EmailOpen 然后 它通过我的转换器发送。 (然后它中断了,因为我的条件检查下划线,而 EmailOpen.ToString() 没有下划线。)


那么我的问题是: 为什么它在没有我的转换器的情况下进行转换,我该如何停止它?我只希望它只使用我的转换器

我认为您的转换器正在调用 -- 它只是无法正常工作。问题在于,您不是从 JsonReader reader 中读取新值,而是使用 existingValue 中的值。但是这第二个值是class中预先存在的属性值被反序列化,不是正在读取的值。

您需要按照 Json.NET 的 StringEnumConverter 从 reader 加载值。这是一个执行此操作的版本,它还通过 subclassing StringEnumConverter 并将从文件读取的值传递给基础 class 以进行进一步处理来处理枚举的标准值:

public class ActivityTypeConverter : StringEnumConverter
{
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        bool isNullable = (Nullable.GetUnderlyingType(objectType) != null);
        Type type = (Nullable.GetUnderlyingType(objectType) ?? objectType);

        if (reader.TokenType == JsonToken.Null)
        {
            if (!isNullable)
                throw new JsonSerializationException();
            return null;
        }

        var token = JToken.Load(reader);
        if (token.Type == JTokenType.String)
        {
            var rawString = ((string)token).ToLower();
            if (rawString.Contains("click"))
                return ActivityType.LinkClick;
            else if (rawString.Contains("salesforce"))
                return ActivityType.Salesforce;
            else if (rawString.Contains("email_open"))
                return ActivityType.EmailOpen;
        }

        using (var subReader = token.CreateReader())
        {
            while (subReader.TokenType == JsonToken.None)
                subReader.Read();
            try
            {
                return base.ReadJson(subReader, objectType, existingValue, serializer); // Use base class to convert
            }
            catch (Exception ex)
            {
                return ActivityType.Unsupported;
            }
        }
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(ActivityType);
    }
}