下载地址: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 () {
}
}