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);
}
}
在我的 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);
}
}