在Unity中使用NewtonJson时,如果要序列化的类继承了别的类,可能报如下错误:
JsonSerializationException: Self referencing loop detected for property......
解决的方法是新建一个JsonSerializerSettings对象,并设置对象的ReferenceLoopHandling参数为:ReferenceLoopHandling.Ignore,然后在序列化时将这个对象作为参数添加进去。参考如下:
var settings = new JsonSerializerSettings();
settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
string json = JsonConvert.SerializeObject(infos, settings);
如果我们要序列化一个基类的数组,由于子类可能会出现参数相同,但是类型不同的问题,最好在JsonSerializerSettings对象里面设置TypeNameHandling的值为TypeNameHandling.Auto,这样NewtonJson序列化时会在必要的情况下添加对象的类型信息。参考如下:
var settings = new JsonSerializerSettings();
settings.TypeNameHandling = TypeNameHandling.Auto;
settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
string json = JsonConvert.SerializeObject(infos, settings);
序列化的结果参考如下:
[
{
"$type": "BoxColliderInfo, Assembly-CSharp",
"size": {
"x": 1.0,
"y": 1.0,
"z": 1.0,
"normalized": {
"x": 0.577350259,
"y": 0.577350259,
"z": 0.577350259,
"magnitude": 1.0,
"sqrMagnitude": 0.99999994
},
"magnitude": 1.73205078,
"sqrMagnitude": 3.0
},
"center": {
"x": 0.0,
"y": 1.0,
"z": 0.0,
"magnitude": 1.0,
"sqrMagnitude": 1.0
},
"cip": "0"
},
{
"$type": "SphereColliderInfo, Assembly-CSharp",
"radius": 2.5,
"center": {
"x": 1.0,
"y": 0.0,
"z": 0.0,
"magnitude": 1.0,
"sqrMagnitude": 1.0
},
"cip": "1"
}
]
需要注意的是,这里面添加了"$type"字段,这是为了在反序列化是能得到正确类型的对象。
最后需要说的是,在序列化和反序列化时应该使用相同的JsonSerializerSettings对象设置。于是我写了一个类来简化使用NewtonJson的代码,参考如下:
using Newtonsoft.Json;
public class JsonTool
{
static JsonSerializerSettings settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto, ReferenceLoopHandling = ReferenceLoopHandling.Ignore};
public static string ToJson(object obj) { return JsonConvert.SerializeObject(obj, settings);}
public static T FromJson<T>(string json) { return JsonConvert.DeserializeObject<T>(json, settings); }
}
现在,我们使用JsonTool.ToJson和JsonTool.FromJson就可以了。
如果你之前使用的是Unity内置的JsonUtility,现在直接用JsonTool搜索并替换JsonUtility就可以了。
//----------------------------------------------------------------------------------------------------------------------------
好吧,其实还是有问题。
本来以为万事大吉了,结果发现NewtonJson有个很神奇的错误,如果我给一个Color变量赋值,如果里面的rgba值为0或者为1就没有问题,如果是0到1之间的浮点数,Unity就直接退出,出这个问题的时候一直以为是别的方面的错误,最后一行代码一行代码的测试,才发现居然是NewtonJson的问题,最后想了个别的办法,所有用于序列化的类里面的Color都改成自定义的Vector4D,这样就不会出错,只不过要重载一大堆运算符,尤其是Vector4D,既要重载Vector4D和Vector4之间的操作,又要重载Vector4D和Color之间的操作,本来还想重载Vector4D和Quaternion之间的操作,感觉不大可能序列化Quaternion方面的东西,算了。
当时序列化的时候还发现一个问题,就是序列化Vector3的时候会把Vector3对象的magnitude和sqrMagnitude的值也序列化了,这个是没有必要的,所以干脆在用于序列化的类里面把Vector3用Vector3D替代,把Vector2用Vector2D替代,这样序列化出来的内容就简洁而且不报错了。就是上面代码中的那行
settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
可以不用写了。
所定义的Vector2D、Vector3D、Vector4D参考如下:
using System;
using UnityEngine;
[Serializable]
public class TranP
{
public Vector3D position = Vector3.zero;
public TranP(Vector3 position)
{
this.position = position;
}
public TranP() { position = Vector3.zero; }
}
[Serializable]
public class TranPR : TranP
{
public Vector3D euler = Vector3.zero;
public TranPR(Vector3 position, Vector3 euler) : base(position)
{
this.euler = euler;
}
public TranPR() : base() { euler = Vector3.zero; }
public Quaternion GetRotation() { return Quaternion.Euler(euler); }
}
[Serializable]
public class TranPRS : TranPR
{
public Vector3D scale = Vector3.one;
public TranPRS(Vector3 position, Vector3 euler, Vector3 scale) : base(position, euler)
{
this.scale = scale;
}
public TranPRS() : base() { scale = Vector3.one; }
}
[Serializable]
public class TranNP : TranP
{
public string name;
public TranNP(string name, Vector3 position) : base(position)
{
this.name = name;
}
}
[Serializable]
public class TranNPR : TranPR
{
public string name;
public TranNPR(string name, Vector3 position, Vector3 euler) : base(position, euler)
{
this.name = name;
}
}
[Serializable]
public class TranNPRS : TranPRS
{
public string name;
public TranNPRS(string name, Vector3 position, Vector3 euler, Vector3 scale) : base(position, euler, scale)
{
this.name = name;
}
}
[Serializable]
public class CamRot
{
public float rotH;
public float rotV;
public CamRot(float rotH, float rotV) { this.rotH = rotH; this.rotV = rotV; }
}
[Serializable]
public class TranCam
{
public Vector3D position;
public CamRot camRot;
public TranCam(Vector3 position, CamRot camRot)
{
this.position = position;
this.camRot = camRot;
}
}
[Serializable]
public class Vector2D
{
public float x;
public float y;
public Vector2D()
{
x = 0;
y = 0;
}
public Vector2D(float x, float y)
{
this.x = x;
this.y = y;
}
public float GetSqrtMagnitude()
{
return x * x + y * y;
}
public float GetMagnitude()
{
return Mathf.Sqrt(GetSqrtMagnitude());
}
public static implicit operator Vector2D(Vector2 v)
{
return new Vector2D(v.x, v.y);
}
public static implicit operator Vector2(Vector2D v)
{
return new Vector2(v.x, v.y);
}
public static Vector2D operator +(Vector2D v1, Vector2D v2)
{
return new Vector2D(v1.x + v2.x, v1.y + v2.y);
}
public static Vector2D operator -(Vector2D v1, Vector2D v2)
{
return new Vector2D(v1.x - v2.x, v1.y - v2.y);
}
public static Vector2D operator *(Vector2D v, float f)
{
return new Vector2D(v.x * f, v.y * f);
}
public static Vector2D operator /(Vector2D v, float f)
{
return new Vector2D(v.x / f, v.y / f);
}
public static Vector2D operator +(Vector2D v1, Vector2 v2)
{
return new Vector2D(v1.x + v2.x, v1.y + v2.y);
}
public static Vector2D operator -(Vector2D v1, Vector2 v2)
{
return new Vector2D(v1.x - v2.x, v1.y - v2.y);
}
public static Vector2D operator +(Vector2 v1, Vector2D v2)
{
return new Vector2D(v1.x + v2.x, v1.y + v2.y);
}
public static Vector2D operator -(Vector2 v1, Vector2D v2)
{
return new Vector2D(v1.x - v2.x, v1.y - v2.y);
}
}
[Serializable]
public class Vector3D
{
public float x;
public float y;
public float z;
public Vector3D()
{
x = 0;
y = 0;
z = 0;
}
public Vector3D(float x, float y, float z)
{
this.x = x;
this.y = y;
this.z = z;
}
public float GetSqrtMagnitude()
{
return x * x + y * y + z * z;
}
public float GetMagnitude()
{
return Mathf.Sqrt(GetSqrtMagnitude());
}
public static implicit operator Vector3D(Vector3 v)
{
return new Vector3D(v.x, v.y, v.z);
}
public static implicit operator Vector3(Vector3D v)
{
return new Vector3(v.x, v.y, v.z);
}
public static Vector3D operator +(Vector3D v1, Vector3D v2)
{
return new Vector3D(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z);
}
public static Vector3D operator -(Vector3D v1, Vector3D v2)
{
return new Vector3D(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z);
}
public static Vector3D operator *(Vector3D v, float f)
{
return new Vector3D(v.x * f, v.y * f, v.z * f);
}
public static Vector3D operator /(Vector3D v, float f)
{
return new Vector3D(v.x / f, v.y / f, v.z / f);
}
public static Vector3D operator +(Vector3D v1, Vector3 v2)
{
return new Vector3D(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z);
}
public static Vector3D operator -(Vector3D v1, Vector3 v2)
{
return new Vector3D(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z);
}
public static Vector3D operator +(Vector3 v1, Vector3D v2)
{
return new Vector3D(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z);
}
public static Vector3D operator -(Vector3 v1, Vector3D v2)
{
return new Vector3D(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z);
}
}
[Serializable]
public class Vector4D
{
public float r;
public float g;
public float b;
public float a;
public Vector4D() { r = 1; g = 1; b = 1; a = 1; }
public Vector4D(float r, float g, float b, float a)
{
this.r = r;
this.g = g;
this.b = b;
this.a = a;
}
public static implicit operator Vector4D(Color c)
{
return new Vector4D(c.r, c.g, c.b, c.a);
}
public static implicit operator Color(Vector4D c)
{
return new Color(c.r, c.g, c.b, c.a);
}
public static Vector4D operator +(Vector4D v1, Vector4D v2)
{
return new Vector4D(v1.r + v2.r, v1.g + v2.g, v1.b + v2.b, v1.a + v2.a);
}
public static Vector4D operator -(Vector4D v1, Vector4D v2)
{
return new Vector4D(v1.r - v2.r, v1.g - v2.g, v1.b - v2.b, v1.a - v2.a);
}
public static Vector4D operator *(Vector4D v, float f)
{
return new Vector4D(v.r * f, v.g * f, v.b * f, v.a * f);
}
public static Vector4D operator /(Vector4D v, float f)
{
return new Vector4D(v.r / f, v.g / f, v.b / f, v.a / f);
}
public static Vector4D operator +(Vector4D v1, Vector4 v2)
{
return new Vector4D(v1.r + v2.x, v1.g + v2.y, v1.b + v2.z, v1.a + v2.w);
}
public static Vector4D operator -(Vector4D v1, Vector4 v2)
{
return new Vector4D(v1.r - v2.x, v1.g - v2.y, v1.b - v2.z, v1.a - v2.w);
}
public static Vector4D operator +(Vector4 v1, Vector4D v2)
{
return new Vector4D(v1.x + v2.r, v1.y + v2.g, v1.z + v2.b, v1.w + v2.a);
}
public static Vector4D operator -(Vector4 v1, Vector4D v2)
{
return new Vector4D(v1.x - v2.r, v1.y - v2.g, v1.z - v2.b, v1.w - v2.a);
}
}
希望这次没有问题了吧。
//----------------------------------------------------------------------------------------------------------------------------
不是的,还有一些小问题,代码里面有些地方用的是Vector3的magnitude,但是Vector3D里面没有,关键是我不能加这个属性啊,一加这个属性,序列化又多出magnitude和sqrtMagnitude这个内容了,所以如果需要的化,就添加一个GetMagnitude()方法和GetSqrtMagnitude()方法替代,或者用Vector3.Distance方法解决吧,有些地方需要Quaternion对象作为返回属性的就写个GetQuaternion()方法替代吧。
希望没问题了,呵呵。
//----------------------------------------------------------------------------------------------------------------------------
好吧,我又幼稚了,原来的Vector3是struct,但是现在定义的Vector3D之类的都是class,由于class允许设置位null,但是struct不行,所以如果当Vector3D的对象为null的时候,如果赋值给一个Vector3对象,会出现莫名奇妙的运行错误,并且不提示!比如说for循环或者foreach循环执行到这个赋值的位置直接跳出去!疯了!!疯了!!!
后来查看了一下相关代码,应该是这样的,当class的对象为null赋值给一个struct时,就会导致执行错误,比如说莫名其妙的跳出循环,因为struct不可能是null啊,关键是不报错,后面的还能正常执行,也是醉了。
所以最终的代码应该是把class都换成struct,就像下面这样的:
[Serializable]
public struct Vector2D
{
public float x;
public float y;
public Vector2D(float x, float y)
{
this.x = x;
this.y = y;
}
public readonly float GetSqrtMagnitude()
{
return x * x + y * y;
}
public readonly float GetMagnitude()
{
return Mathf.Sqrt(GetSqrtMagnitude());
}
public static implicit operator Vector2D(Vector2 v)
{
return new Vector2D(v.x, v.y);
}
public static implicit operator Vector2(Vector2D v)
{
return new Vector2(v.x, v.y);
}
public static Vector2D operator +(Vector2D v1, Vector2D v2)
{
return new Vector2D(v1.x + v2.x, v1.y + v2.y);
}
public static Vector2D operator -(Vector2D v1, Vector2D v2)
{
return new Vector2D(v1.x - v2.x, v1.y - v2.y);
}
public static Vector2D operator *(Vector2D v, float f)
{
return new Vector2D(v.x * f, v.y * f);
}
public static Vector2D operator /(Vector2D v, float f)
{
return new Vector2D(v.x / f, v.y / f);
}
public static Vector2D operator +(Vector2D v1, Vector2 v2)
{
return new Vector2D(v1.x + v2.x, v1.y + v2.y);
}
public static Vector2D operator -(Vector2D v1, Vector2 v2)
{
return new Vector2D(v1.x - v2.x, v1.y - v2.y);
}
public static Vector2D operator +(Vector2 v1, Vector2D v2)
{
return new Vector2D(v1.x + v2.x, v1.y + v2.y);
}
public static Vector2D operator -(Vector2 v1, Vector2D v2)
{
return new Vector2D(v1.x - v2.x, v1.y - v2.y);
}
}
[Serializable]
public struct Vector3D
{
public float x;
public float y;
public float z;
public Vector3D(float x, float y, float z)
{
this.x = x;
this.y = y;
this.z = z;
}
public readonly float GetSqrtMagnitude()
{
return x * x + y * y + z * z;
}
public readonly float GetMagnitude()
{
return Mathf.Sqrt(GetSqrtMagnitude());
}
public static implicit operator Vector3D(Vector3 v)
{
return new Vector3D(v.x, v.y, v.z);
}
public static implicit operator Vector3(Vector3D v)
{
return new Vector3(v.x, v.y, v.z);
}
public static Vector3D operator +(Vector3D v1, Vector3D v2)
{
return new Vector3D(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z);
}
public static Vector3D operator -(Vector3D v1, Vector3D v2)
{
return new Vector3D(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z);
}
public static Vector3D operator *(Vector3D v, float f)
{
return new Vector3D(v.x * f, v.y * f, v.z * f);
}
public static Vector3D operator /(Vector3D v, float f)
{
return new Vector3D(v.x / f, v.y / f, v.z / f);
}
public static Vector3D operator +(Vector3D v1, Vector3 v2)
{
return new Vector3D(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z);
}
public static Vector3D operator -(Vector3D v1, Vector3 v2)
{
return new Vector3D(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z);
}
public static Vector3D operator +(Vector3 v1, Vector3D v2)
{
return new Vector3D(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z);
}
public static Vector3D operator -(Vector3 v1, Vector3D v2)
{
return new Vector3D(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z);
}
}
[Serializable]
public struct Vector4D
{
public float r;
public float g;
public float b;
public float a;
public Vector4D(float r, float g, float b, float a)
{
this.r = r;
this.g = g;
this.b = b;
this.a = a;
}
public static implicit operator Vector4D(Color c)
{
return new Vector4D(c.r, c.g, c.b, c.a);
}
public static implicit operator Color(Vector4D c)
{
return new Color(c.r, c.g, c.b, c.a);
}
public static Vector4D operator +(Vector4D v1, Vector4D v2)
{
return new Vector4D(v1.r + v2.r, v1.g + v2.g, v1.b + v2.b, v1.a + v2.a);
}
public static Vector4D operator -(Vector4D v1, Vector4D v2)
{
return new Vector4D(v1.r - v2.r, v1.g - v2.g, v1.b - v2.b, v1.a - v2.a);
}
public static Vector4D operator *(Vector4D v, float f)
{
return new Vector4D(v.r * f, v.g * f, v.b * f, v.a * f);
}
public static Vector4D operator /(Vector4D v, float f)
{
return new Vector4D(v.r / f, v.g / f, v.b / f, v.a / f);
}
public static Vector4D operator +(Vector4D v1, Vector4 v2)
{
return new Vector4D(v1.r + v2.x, v1.g + v2.y, v1.b + v2.z, v1.a + v2.w);
}
public static Vector4D operator -(Vector4D v1, Vector4 v2)
{
return new Vector4D(v1.r - v2.x, v1.g - v2.y, v1.b - v2.z, v1.a - v2.w);
}
public static Vector4D operator +(Vector4 v1, Vector4D v2)
{
return new Vector4D(v1.x + v2.r, v1.y + v2.g, v1.z + v2.b, v1.w + v2.a);
}
public static Vector4D operator -(Vector4 v1, Vector4D v2)
{
return new Vector4D(v1.x - v2.r, v1.y - v2.g, v1.z - v2.b, v1.w - v2.a);
}
}
哈哈,这绝对是最后一次修改!!