下載地址: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對象,我們沒有對Name
和Attribute
賦值,又因爲這兩種類型都爲引用模式,所以存儲的爲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 () {
}
}