创建一个自定义JsonConverter来处理System.Text.Encoding对象
本文关键字:处理 System Text 对象 Encoding JsonConverter 自定义 一个 创建 | 更新日期: 2023-09-27 18:04:32
我已经编写了一个自定义的JsonConverter,我希望它将允许我在我的类中序列化和反序列化Encoding
对象:
public class EncodingConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType.IsSubclassOf(typeof(Encoding));
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteValue(((Encoding)value).EncodingName);
}
public override bool CanRead { get { return true; } }
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var name = reader.ReadAsString();
return Encoding.GetEncoding(name);
}
}
然而,当我运行下面的测试代码时,我在调用DeserializeObject
时得到一个异常,并且ReadJson
方法从未被调用。
class Program
{
private static void Main(string[] args)
{
var test = new TestClass();
var jsonSettings = new JsonSerializerSettings
{
Converters = new[] { new EncodingConverter(), }
};
var json = JsonConvert.SerializeObject(test, jsonSettings);
var test2 = JsonConvert.DeserializeObject<TestClass>(json, jsonSettings);
}
}
class TestClass
{
public string Property1;
public Encoding Encoding = Encoding.UTF8;
}
异常消息为:
目标类型System.Text.Encoding不是值类型或非抽象类。
我错过了什么吗?
我看到你的转换器有三个问题。
- 您在
CanConvert()
中使用了错误的检查。 - 您在序列化时使用了错误的
Encoding
名称。 - 在反序列化时,您使用了错误的方法从读取器获取值。
让我们一个一个来。
首先,在CanConvert
方法中,您使用objectType.IsSubclassOf(typeof(Encoding))
来确定转换器是否应该处理Encoding
。这在序列化中工作得很好,因为你有一个具体的编码实例(例如UTF8Encoding
),它实际上是Encoding
的子类。然而,在反序列化时,反序列化器并不知道您将要进行的编码的具体类型,因此传递给转换器的类型只是Encoding
。由于Encoding
不是自身的子类,因此CanConvert
返回false,并且您的ReadJson
方法永远不会被调用。这样就剩下Json了。Net试图实例化Encoding
本身,它不能这样做(因为Encoding
是抽象的),所以它抛出你在你的问题中提到的错误。你应该在你的CanConvert
方法中使用typeof(Encoding).IsAssignableFrom(objectType)
。
第二,当在WriteJson
中序列化Encoding
时,您输出的是EncodingName
属性,这是编码的人类可读的显示名称,而不是代码页名称。如果您查看Encoding.GetEncoding(string)
方法的文档,它说:
参数<
名称/em>
类型:系统。字符串
首选编码的代码页名称。WebName属性返回的任何值都是有效的。可能的值列在出现在Encoding类主题中的表的Name列中。
因此,如果您希望能够使用该值在ReadJson
中重建Encoding
,则应该在WriteJson
方法中输出WebName
属性的值。
第三,在您的ReadJson
方法中,您使用reader.ReadAsString()
尝试从JSON中获取编码名称。这不会像你期望的那样工作。当ReadJson
被Json调用时。Net时,阅读器已经定位在当前值。当调用ReadAsString()
时,它会将读取器推进到下一个标记,然后尝试将该标记解释为字符串。您真正想要做的只是获取当前令牌的值,这可以使用Value
属性来完成。因为Value
是object
类型,所以需要将其强制转换为字符串。
以下是转换器的更正代码:
public class EncodingConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(Encoding).IsAssignableFrom(objectType);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteValue(((Encoding)value).WebName);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return Encoding.GetEncoding((string)reader.Value);
}
}
小提琴:https://dotnetfiddle.net/UmLynX
尝试:
public class CustomConverter : JsonConverter
{
public override bool CanConvert(System.Type objectType)
{
return true;// objectType.IsAssignableFrom(typeof(Encoding));
}
public override object ReadJson(JsonReader reader, System.Type objectType, object existingValue, JsonSerializer serializer)
{
return Encoding.GetEncoding(Convert.ToString(reader.Value));
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var t = (Test)value;
var e = (Encoding)t.MyProperty;
writer.WriteValue(e.BodyName);
//serializer.Serialize(writer, e.BodyName);
}
}
在Main
:
var o = new Test { MyProperty = Encoding.UTF8 };
var s = new JsonSerializerSettings
{
Converters = new[] { new CustomConverter() }
};
var v = JsonConvert.SerializeObject(o, s);
var o2 = new Test();
o2.MyProperty = Encoding.GetEncoding(JsonConvert.DeserializeObject(v, s).ToString());