Unity中使用NewtonJson序列化继承类时报错解决方法参考

36 篇文章 1 订阅

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

        哈哈,这绝对是最后一次修改!!

  • 6
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值