ToTxt 序列化方法

下載地址:https://pan.baidu.com/s/1sKnnDNKr2tyNd0NIpXsagA 提取碼:9e76
測試工程:https://pan.baidu.com/s/1Dk68RQe1ZMIarjgHmjG0VQ 提取碼:n22s

ToTxt 是一種將C# 對象轉爲txt的一種序列化方法。
ToTxt 可以以下字段的轉換:
需要序列化的C#對象,必須實現:[TXTClass]屬性,且需要實現序列化的字段必須實現[TXTField]屬性且訪問權限爲public
這個兩個屬性表明,該對象或字段需要序列化。
[TXTField]屬性有一個Alias字段,該字段可以爲需要序列化的字段提供一個別名,別名可以防止代碼混淆後,無法實現反序列化的問題。如果未指定別名,將會使用字段的名稱。

ToTxt 支持大部分的數據格式以及數據結構:

1.Enum 類型
2.基元類型(float,int,bool,double 等)
3.字符串(string)
4.結構(struct)
5.類(class)
6.數組
7.List
8.Dictionary

複雜List:
List<List<string>> |List<string[]> |List<Dictionary<string,int>>等
以及複雜的Dictionary:
Dictionary<string,string>|Dictionary<string,string[]>|Dictionary<string,List<int>>|Dictionary<string,Dictionary<string,int>>等

**不支持多維數組**

ToTxt 中分爲兩部分:
1.ToTxt ,這個類爲靜態類,主要實現對C#對象序列化和反序列化的實現

方法 描述
string Serialization(object target) 序列化目標對象
SeriElement(object item) 序列化任意目標對象
T Deserialization(string value) 反序列化
object DeseriElement(string value,Type fieldType) 反序列化任何目標
TXTParser TXTParse(string value) 獲取TXT解析器

例如:


		[TXTClass]
		public class CObject
		{
			[TXTField("ObjectName")] public string Name;
			[TXTField] public int Level;
		}

		CObject o = new CObject ();
		o.Name = "Unity";
		o.Level = 10;
		string value = ToTxt.Serialization (o);

		CObject t = ToTxt.Deserialization<CObject> (value);
		Debug.Log (t.Name);
		Debug.Log (t.Level);

2.TXTParser txt解析器,可以手動對所需字段進行序列化或反序列化:

方法 描述
void Add(string key,object value) 添加字段
string Serialization() 序列化
void Deserialization(string value) 反序列化
string this[string key] 根據key獲取對應的序列txt
bool ContainsKey(string key) 判斷是否包含這個key
T Convert(string value) 將序列txt 轉爲對象

例如:

		TXTParser parser = new TXTParser ();
		parser.Add ("ID", 20);
		parser.Add ("Name", "Unity");
		string value = parser.Serialization ();
		TXTParser t = new TXTParser ();
		t.Deserialization (value);
		int id = t.Convert<int> (t ["ID"]);
		string name = t ["Name"];
		Debug.Log (id);
		Debug.Log (name);

序列化後的文本格式:
例如,有以下代碼:

///Object 類型
public enum CObjectType
{
	Enemy,
	Player
}

///Object 配置
[TXTClass]
public struct CObjectConfig
{
	[TXTField] public float Speed;
	[TXTField] public int AssetID;

}
///Object 屬性
[TXTClass]
public class CObjectAttribute
{
	[TXTField] public int Hp;
	[TXTField] public int MapHp;

	public int Mp = 0;

}
///Ojbect
[TXTClass]
public class CObject
{
	[TXTField("ObjectName")] public string Name;
	[TXTField] public int Level;
	[TXTField] public CObjectType CObjectType;

	[TXTField] public CObjectConfig Config;
	[TXTField] public CObjectAttribute Attribute;

}
public class MonoTEST : MonoBehaviour {

	// Use this for initialization
	void Start () {
		//創建一個CObject
		CObject o = new CObject ();
		o.Name = "Unity";
		o.Level = 10;
		o.CObjectType = CObjectType.Enemy;
		o.Config.Speed = 5;
		o.Config.AssetID = 10;
		o.Attribute = new CObjectAttribute ();
		o.Attribute.Hp = 80;
		o.Attribute.MapHp = 100;
		//序列化
		string value = ToTxt.Serialization (o);
		Debug.Log (value);
	}
}

會得到以下文本:

{
	ObjectName=Unity
	Level=10
	CObjectType=Enemy
	Config="c_0"
	Attribute="c_1"
}

"c_0"={
	Speed=5
	AssetID=10
}

"c_1"={
	Hp=80
	MapHp=100
}

模塊:每一對大括號包圍的內容爲一個模塊
第一模塊,就是對象的主模塊,包含序列化對象中定義的且實現[TXTField]以及訪問級別爲public的字段名稱(或別名)及內容。
因爲在CObject中Name使用了別名 ObjectName,所以此處使用ObjectName作爲字段名存儲。
Config與Attribute 都爲新的結構體(struct,class),所以會額外創建兩個模塊("c_0""c_1"),來保存這個兩個結構內容,使用"c_num"方式的模塊名進行關聯(num爲除主模塊外其他模塊的數量)。
在Attribute中因爲字段Mp沒有使用[TXTField]屬性所以在模塊"c_1"中沒有此字段值。

注意:"c_num" 兩側的雙引號代表着這是個新的模塊,所以不能捨棄。所以在字符串變量賦值時,應避免使用雙引號開始以及結尾,

數組、列表、字典:
例如:

		TXTParser parser = new TXTParser ();
		parser.Add ("IntAry", new int[]{ 1, 2, 3 });
		parser.Add ("IntList", new List<int> (){ 4, 5, 6 });
		parser.Add ("CObjectList", new List<CObject> (){ new CObject (), new CObject () });
		parser.Add ("StringIntDic", new Dictionary<string,int> (){ { "a",1 }, { "b",2 } });
		Debug.Log (parser.Serialization ());

得到以下序列文本:

{
	IntAry=[1,2,3]
	IntList=[4,5,6]
	CObjectList=["c_1","c_3"]
	StringIntDic=[a=1,b=2]
}

"c_0"={
	Speed=0
	AssetID=0
}

"c_1"={
	ObjectName=null
	Level=0
	CObjectType=Enemy
	Config="c_0"
	Attribute=null
}

"c_2"={
	Speed=0
	AssetID=0
}

"c_3"={
	ObjectName=null
	Level=0
	CObjectType=Enemy
	Config="c_2"
	Attribute=null
}

通過文本,我們看到數組與列表的序列化後得到文本基本上是一樣的。如果數組或列表爲結構或類,都會根據對應的元素生產新的模塊,而列表中存儲的是模塊名稱。
因爲新創建的CObject對象,我們沒有對NameAttribute賦值,又因爲這兩種類型都爲引用模式,所以存儲的爲null值。
字典生成的序列文本中,使用=將key和value進行關聯。

反序列化時,會先將整個序列文本,切割成一個個模塊,然後對主模塊(默認鍵爲 “main”)進行解析,並與反序列對象中的字段進行匹配,然後根據字段的 類型,將文本轉爲對應類型。如果,字段是struct或class,會找打對應的模塊,然後對該模塊進行解析。

在使用過程中,應儘量避免自身引用以及父類引用,否則可能會造成死循環

線階段就這麼多的功能,後續可能還會加上加密功能等。

下面爲我寫的測試代碼:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public enum StateType
{
	None,
}

[TXTClass]
public class Test1{
	[TXTField] public int Int;
	[TXTField] public string String;
	[TXTField] public Test2 test2;
	[TXTField] public Test3 test3 = new Test3();
}

[TXTClass]
public class Test3{
	[TXTField] public float Float;
}

[TXTClass]
public struct Test2{

	[TXTField] public int Int;
	[TXTField] public float Float;
}

[TXTClass]
public class Test  {


	[TXTField] public string Name = "text";
	[TXTField("222")] public int Int = 0;
	[TXTField] public float Float = 0;
	[TXTField] public bool Bool = false;
	[TXTField] public double Double = 0;

	[TXTField] public Test1 t1 = new Test1();
	[TXTField] public Test1 t3;
	[TXTField] public Test2 t2;

	[TXTField("haha")] public int[] IntAry = new int[]{1,2,3};
	[TXTField] public int[] IntAry1;
	[TXTField] public float[] FloatAry = new float[]{1.0f,2.0f,3.0f};
	[TXTField] public bool[] BoolAry = new bool[]{false,false,true};
	[TXTField] public string[] StringAry = new string[]{"a","b","c"};
	[TXTField] public List<int> IntList = new List<int>(){1,2,3};
	[TXTField] public Test2[] Test2Ary = new Test2[2];
	[TXTField] public Test1[] Test1Ary = new Test1[]{new Test1(){},new Test1(){}};
	[TXTField] public StateType StateType = StateType.None;
	[TXTField] public List<Test1> Test1List = new List<Test1> (){ new Test1 (), new Test1 () };
	[TXTField] public List<int[]> IntAryList = new List<int[]>(){new int[]{1,2,3}};
	[TXTField] public List<List<string>> StringListList = new List<List<string>>(){new List<string>(){"a","b","c"}};
	[TXTField] public List<List<Test1>> ClassListList = new List<List<Test1>> (){ new List<Test1> () {
			new Test1 (),
			new Test1 ()
		} };
	[TXTField] public Dictionary<string,string> Dic = new Dictionary<string, string>(){{"a","bbbb"},{"b","ccccc"}};
	[TXTField] public Dictionary<string,string[]> DicAry = new Dictionary<string, string[]> () {
		 {
			"a",
			new string[]{ "aa", "bb" }
		},
		 {
			"b",
			new string[] {
				"bb",
				"cc"
			}
		}
	};
	[TXTField] public Dictionary<string,int> DicInt = new Dictionary<string, int> (){ { "a",0 }, { "b",1 },{"c",1}};
	[TXTField] public Dictionary<string,List<Test1>> DicTest1 = new Dictionary<string, List<Test1>> (){ {
			"a",
			new List<Test1> (){ new Test1 () }
		},{"b",new List<Test1>(){new Test1(),new Test1()}} };
	[TXTField] public Dictionary<string,Dictionary<string,int>> DicDic = new Dictionary<string,Dictionary<string,int>> () {
		{ "a",new Dictionary<string,int> (){ { "b",1 } } }
	};
	[TXTField] public List<Dictionary<string,int>> ListDic = new List<Dictionary<string, int>> () {
		new Dictionary<string, int> (){ { "a",1 } }

	};

using UnityEngine;
using System.Collections;
using System;
using System.Collections.Generic;

public enum CObjectType
{
	Enemy,
	Player
}

[TXTClass]
public struct CObjectConfig
{
	[TXTField] public float Speed;
	[TXTField] public int AssetID;

}

[TXTClass]
public class CObjectAttribute
{
	[TXTField] public int Hp;
	[TXTField] public int MapHp;

	public int Mp = 0;

}

[TXTClass]
public class CObject
{
	[TXTField("ObjectName")] public string Name;
	[TXTField] public int Level;
	[TXTField] public CObjectType CObjectType;

	[TXTField] public CObjectConfig Config;
	[TXTField] public CObjectAttribute Attribute;

}

public class MonoTEST : MonoBehaviour {

	// Use this for initialization
	void Start () {

		/*
		CObject o = new CObject ();
		o.Name = "Unity";
		o.Level = 10;
		o.CObjectType = CObjectType.Enemy;
		o.Config.Speed = 5;
		o.Config.AssetID = 10;
		o.Attribute = new CObjectAttribute ();
		o.Attribute.Hp = 80;
		o.Attribute.MapHp = 100;

		string value = ToTxt.Serialization (o);
		Debug.Log (value);
		CObject t = ToTxt.Deserialization<CObject> (value);
		Debug.Log (t.Name);
		Debug.Log (t.Level);
*/
		/*
		Test test = new Test ();
		test.Int = 10;
		test.Double = 20;
		test.IntAry = new int[]{ 7, 89, 5 };
		test.Test1List.Add (new Test1 (){ Int = 5 });
		test.Test1List.Add (new Test1 (){ String = "哈哈" });
		test.DicTest1 ["a"] [0].Int = 30;
		string value = ToTxt.Serialization (test);
		Debug.Log(value);
		Test test1 = ToTxt.Deserialization<Test> (value);
		foreach (var data in test1.DicTest1) {
			for (int i = 0; i < data.Value.Count; i++)
				Debug.Log (data.Key + "=>" + data.Value [i].Int);
		}
		/*
		for (int i = 0; i < test1.Test1List.Count; i++)
			Debug.Log (test1.Test1List [i].Int);
		Test test3 = new Test ();
		TXTParse test2 = ToTxt.TXTParse (value);
		test3.Int = test2.Convert<int> (test2 ["Int"]);
*/
		/*
		TXTParser parser = new TXTParser ();
		parser.Add ("ID", 20);
		parser.Add ("Name", "Unity");
		string value = parser.Serialization ();
		TXTParser t = new TXTParser ();
		t.Deserialization (value);
		int id = t.Convert<int> (t ["ID"]);
		string name = t ["Name"];
		Debug.Log (id);
		Debug.Log (name);

		Debug.Log (value);
		string aaa = "None";
		*/
		//object value = Convert.ChangeType (test, typeof(int));
		//Debug.Log ((int)value);
		//value = Convert.ChangeType(test,typeof(float));
		//Debug.Log ((float)value);
		//object value = Convert.ChangeType(test,typeof(bool));
		//Debug.Log ((bool)value);
		//object value = Enum.Parse(typeof(StateType),test);
		//Debug.Log ((StateType)value);

		TXTParser parser = new TXTParser ();
		parser.Add ("IntAry", new int[]{ 1, 2, 3 });
		parser.Add ("IntList", new List<int> (){ 4, 5, 6 });
		parser.Add ("CObjectList", new List<CObject> (){ new CObject (), new CObject () });
		parser.Add ("StringIntDic", new Dictionary<string,int> (){ { "a",1 }, { "b",2 } });

		Debug.Log (parser.Serialization ());

		/*
		Debug.Log ("IntAry: " + parser ["IntAry"]);
		Debug.Log ("IntList:" + parser ["IntList"]);
		Debug.Log ("CObjectList:" + parser ["CObjectList"]);
		Debug.Log ("StringIntDic" + parser ["StringIntDic"]);
		*/
	}
	
	// Update is called once per frame
	void Update () {
	
	}
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章