第三方类型的Json.NET自定义序列化/反序列化 [英] Json.NET custom serialization/deserialization of a third party type
问题描述
我想将OpenTK库的Vector与JSON相互转换.我认为它的工作方式只是制作一个自定义JsonConverter,所以我这样做了:
I want to converts Vectors of the OpenTK library to and from JSON. The way I thought it worked is just making a custom JsonConverter, so I did this:
class VectorConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(Vector4);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var obj = JToken.Load(reader);
if (obj.Type == JTokenType.Array)
{
var arr = (JArray)obj;
if (arr.Count == 4 && arr.All(token => token.Type == JTokenType.Float))
{
return new Vector4(arr[0].Value<float>(), arr[1].Value<float>(), arr[2].Value<float>(), arr[3].Value<float>());
}
}
return null;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var vector = (Vector4)value;
writer.WriteStartArray();
writer.WriteValue(vector.X);
writer.WriteValue(vector.Y);
writer.WriteValue(vector.Z);
writer.WriteValue(vector.W);
writer.WriteEndArray();
}
}
现在,写"部分对我来说很简单(我认为?).当序列化程序遍历对象时,如果遇到CanConvert方法以true响应的对象,它将使我的自定义序列化程序将其转换为JSON.那行得通.
Now, the Write part is pretty straight forward to me (I think?). When the serializer goes through objects, if it encounters one that the CanConvert method responds to with true, it lets my custom serializer to convert it to JSON. And that works.
我没有真正得到的是另一种方式.由于用JSON文字编写时无法知道某物是什么类型,因此我认为我必须自己分析该对象并确定其是否实际上是Vector对象. 我编写的代码有效,但是如果检查失败,我不知道该怎么办.我如何告诉反序列化器这不是我知道如何翻译的对象之一,而是应该将其作为默认对象?
What I don't really get is the other way. Since there's no way to know what type something is when it's just written in literals in JSON, I thought I have to analyse the object myself and determine if it's in fact the Vector object. The code I've written works, but I don't know what to do if the check fails. How do I tell the deserializer that this isn't one of the objects that I know how to translate and that it should do it's default thing on it?
在整个过程中我是否缺少某些东西?
Am I missing something in how the whole thing works?
推荐答案
在反序列化期间,Json.Net会查看您要反序列化的类,以确定要创建的类型,并扩展确定是否调用转换器. .因此,如果您反序列化为具有Vector4
属性的类,则将调用您的转换器.如果将反序列化为dynamic
或object
或JObject
之类的模糊对象,则Json.Net将不知道调用您的转换器,因此反序列化的对象层次结构将不包含任何Vector4
实例.
During deserialization, Json.Net looks at the classes that you are deserializing into in order to determine what types to create, and by extension, whether to call your converter. So, if you deserialize into a class that has a Vector4
property, your converter will be called. If you deserialize into something nebulous like dynamic
or object
or JObject
, then Json.Net will not know to call your converter, and therefore the deserialized object hierarchy will not contain any Vector4
instances.
让我们举一个简单的例子来使这个概念更加清晰.说我们有这个JSON:
Let's take a simple example to make this concept more clear. Say we have this JSON:
{
"PropA": [ 1.0, 2.0, 3.0, 4.0 ],
"PropB": [ 5.0, 6.0, 7.0, 8.0 ]
}
很明显,上述JSON 中的'PropA'和'PropB'都可以表示Vector4
(或至少我从您的转换器代码中推断为Vector4
的东西-实际上不熟悉OpenTK库).但是,正如您所注意到的那样,JSON中没有任何类型信息,它指出任一属性都应为Vector4
.
Clearly, both 'PropA' and 'PropB' in the above JSON could represent a Vector4
(or at least what I infer to be a Vector4
from your converter code-- I am not actually familiar with the OpenTK library). But, as you noticed, there is no type information in the JSON that says that either property should be a Vector4
.
让我们尝试使用您的转换器将JSON反序列化为以下类.在这里,PropA
必须包含Vector4
或null,因为它是强类型的,而PropB
可以是任何东西.
Let's try to deserialize the JSON into the following class using your converter. Here, PropA
must contain a Vector4
or null since it is strongly typed, while PropB
could be anything.
public class Tester
{
public Vector4 PropA { get; set; }
public object PropB { get; set; }
}
这是测试代码:
class Program
{
static void Main(string[] args)
{
string json = @"
{
""PropA"": [ 1.0, 2.0, 3.0, 4.0 ],
""PropB"": [ 5.0, 6.0, 7.0, 8.0 ]
}";
try
{
Tester t = JsonConvert.DeserializeObject<Tester>(json),
new VectorConverter());
DumpObject("PropA", t.PropA);
DumpObject("PropB", t.PropB);
}
catch (Exception ex)
{
Console.WriteLine(ex.GetType().Name + ": " + ex.Message);
}
}
static void DumpObject(string prop, object obj)
{
if (obj == null)
{
Console.WriteLine(prop + " is null");
}
else
{
Console.WriteLine(prop + " is a " + obj.GetType().Name);
if (obj is Vector4)
{
Vector4 vector = (Vector4)obj;
Console.WriteLine(" X = " + vector.X);
Console.WriteLine(" Y = " + vector.Y);
Console.WriteLine(" Z = " + vector.Z);
Console.WriteLine(" W = " + vector.W);
}
else if (obj is JToken)
{
foreach (JToken child in ((JToken)obj).Children())
{
Console.WriteLine(" (" + child.Type + ") "
+ child.ToString());
}
}
}
}
}
// Since I don't have the OpenTK library, I'll use the following class
// to stand in for `Vector4`. It should look the same to your converter.
public class Vector4
{
public Vector4(float x, float y, float z, float w)
{
X = x;
Y = y;
Z = z;
W = w;
}
public float W { get; set; }
public float X { get; set; }
public float Y { get; set; }
public float Z { get; set; }
}
当我运行测试代码时,这是我得到的输出:
When I run the test code, here is the output I get:
PropA is a Vector4
X = 1
Y = 2
Z = 3
W = 4
PropB is a JArray
(Float) 5
(Float) 6
(Float) 7
(Float) 8
因此,您可以看到,对于PropA
,Json.Net使用转换器创建了Vector4
实例(否则我们将得到一个JsonSerializationException),而对于PropB
,它并没有(否则,我们将在输出中看到PropB is a Vector4
.
So you can see, for PropA
, Json.Net used the converter to create the Vector4
instance (otherwise we would have gotten a JsonSerializationException), while for PropB
, it did not (otherwise, we would have seen PropB is a Vector4
in the output).
对于问题的第二部分,如果给转换器提供的JSON不是预期的,该怎么办.您有两种选择-像执行操作一样返回null或引发异常(例如JsonSerializationException).如果正在调用您的转换器,则您知道Json.Net正在尝试填充Vector4
对象.如果不是,则将不会调用您的转换器.因此,如果由于JSON错误而无法填充它,则必须确定Vector4
为null是可接受的,还是更好地进行错误输出.这是一个设计决定,取决于您要在项目中尝试做什么.
As for the second part of your question, what to do if your converter is given JSON that is not what it is expecting. You have two choices-- return null, like you are doing, or throw an exception (such as a JsonSerializationException). If your converter is being called, you know that Json.Net is trying to populate a Vector4
object. If it were not, then your converter would not have been called. So, if you can't populate it because the JSON is wrong, you have to decide whether it is acceptable that the Vector4
be null, or is it better to error out. It is a design decision that depends on what you are trying to do in your project.
我已经清楚地解释了吗?
Have I explained that clearly?
这篇关于第三方类型的Json.NET自定义序列化/反序列化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!