模仿protobuf的对象序列化系统
来源:互联网 发布:ubuntu 字库 编辑:程序博客网 时间:2024/06/06 03:36
下面都用C#语言举例。其他语言可以参考。
protobuf的优势以及缺点
protocolbuffer(以下简称PB)是google 的一种数据交换的格式,它独立于语言,独立于平台。源代码开源。
优点
1. 速度快,数据小。相同的对象,使用PB比其他类似json,xml等,数据量更小。
2. 兼容性。PB格式有前向与后向兼容性。数据存储之后,如果数据协议更改了,老的数据依然可以读取。而老的协议,也可以读取新的协议产生的数据。这一点上,json与xml都可以达到目的,而二进制格式就不行了。但是二进制格式序列化速度更快,数据更小。但是兼容性差很致命。protobuf就相当于二进制格式的改进版。解决了二进制格式兼容性问题。
缺点
目前来看,protobuf能满足大多数需求,但是某些情况下,protobuf不能满足需求。
1.继承类。
2.循环引用。
这两点都是protobuf不能完成的。
设计的目标:
接近protobuf的性能,同时弥补不足。
设计实现:
1.Tag,WireType
这两个字段标记都与protobuf的功能类似。但是,会有一点更改。
1.Tag标记除了在字段上标记,同时需要在类上标记,因为类也需要一个Tag,一个类与其所有父类的Tag必须不同。这样在反序列化的时候,可以直到一个Field所属哪个类。
2. WireType表示数据类型。设计WireType的宗旨是,获取WireType就知道后面数据的长度。
这里命名为TypeIndex
public enumTypeIndex
{
None, //错误的类型
List, //数组
Object, //对象,包含子对象。
RefObject, //引用对象
Map, //Dictionary
//Variant,
String, //字符串
Fixed8, //8位数值
Fixed32, //32位数值
Fixed64, //64位数值
Custom //自定义数据
}
看一下SkillField方法,从这里可以看出每个WireType的格式。
object SkipField()
{
TypeIndex typeIndex;
TagType tag;
ReadFieldHeader(out tag,out typeIndex);
switch (typeIndex)
{
case TypeIndex.Fixed32:
ms.Position += 4;
break;
case TypeIndex.Fixed64:
ms.Position += 8;
break;
case TypeIndex.Fixed8:
ms.Position += 1;
break;
case TypeIndex.RefObject:
DeserializeRefObject();
break;
case TypeIndex.String:
ReadString();
break;
case TypeIndex.List:
{
int count = reader.ReadInt32();
for (int i = 0; i < count; i++)
{
SkipField();
}
}
break;
case TypeIndex.Map:
{
int count = reader.ReadInt32();
for (int i = 0; i < count; i++)
{
SkipField();
SkipField();
}
}
break;
case TypeIndex.Object:
{
int count = reader.ReadInt32();
for (int i = 0; i < count; i++)
{
SkipField();
}
}
break;
case TypeIndex.Custom:
{
int size = reader.ReadInt32();
ms.Position += size;
}
break;
}
return null;
}
序列化子类的方法:
一个对象,从基类开始到当前对象的真实类结束,依次序列化每个类的数据。
也同时把类的类型,当最自定义字段(Custom),写入到对象数据中。这样在反序列化这个类的时候,就可以反序列化类的运行时类型。
序列化循环引用的方法:
保持一个已经序列化的对象的列表,如果当前正在序列化的对象已经被序列化过了,则此对象当做一个引用类型(RefObject)进行序列化,写入对象在列表的索引。返序列化的时候,这个索引就可以获取真实对象。
关键代码:
(序列化)
protected virtual void SerializeObject(object value,TagType tag)
{
//null值
if(value == null)
{
WriteFieldHeader(TypeIndex.Object, tag);
writer.Write(-1);
return;
}
//引用类型值
if (IsReferenceType(value.GetType()))
{
if (AsReference(value) || Objects.Contains(value))
{
WriteFieldHeader(TypeIndex.RefObject, tag);
SerializeRefObject(value);
return;
}
//添加此引用
Objects.Add(value);
}
List<Type> Types =new List<Type>();
List<TagType> Tags =new List<TagType>();
Type baseType = value.GetType();
while(baseType!=null)
{
ContractAttribute ca =CompatibleAPI.GetCustomAttribute<ContractAttribute>(baseType);
if(ca!=null)
{
Types.Add(baseType);
Tags.Add(ca.Tag);
baseType = baseType.BaseType;
}
else
{
break;
}
}
if(Types.Count == 0)
{
throw new Exception(string.Format("要序列化的类型 {0}没有标记序列化属性Contract", value.GetType().Name));
}
WriteFieldHeader(TypeIndex.Object, tag);
writer.Write(Types.Count+2); //多二个域写入类型
//对象类型
WriteFieldHeader(TypeIndex.Custom, object_type_tag);
SaveType(value.GetType());
//自定义数据
WriteFieldHeader(TypeIndex.Custom, object_custom_tag);
WriteObjectCustomData(value);
for (int i=0;i<Types.Count;i++)
{
SerializeObjectTyped(value, Tags[i], Types[i]);
}
}
void SerializeObjectTyped(object value,TagType tag,Type type)
{
Dictionary<TagType,FieldInfo> fieldDic = new Dictionary<TagType,FieldInfo>();
FieldInfo[] fi = type.GetFields(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public |BindingFlags.NonPublic);
foreach (var vin fi)
{
if(v.DeclaringType == type)
{
MemberAttribute attr =CompatibleAPI.GetCustomAttribute<MemberAttribute>(v);
if (attr != null && IsSupportedField(v,attr))
{
fieldDic.Add(attr.Tag, v);
}
}
}
WriteFieldHeader(TypeIndex.Object, tag);
writer.Write(fieldDic.Count);
foreach (var vin fieldDic)
{
SerializeCore(v.Value.GetValue(value), v.Value.FieldType, v.Key);
}
}
//value type 不能同时为null
void SerializeCore(object value,Type type,TagType tag)
{
if(value!=null)
{
type = value.GetType();
}
if(type == null)
{
throw new ArgumentException("type == null");
}
TypeCode tc = Type.GetTypeCode(type);
TypeIndex ti = GetWireTypeIndex(type);
if (type.IsEnum)
{
//int32
WriteFieldHeader(ti, tag);
writer.Write((int)value);
return;
}
switch (tc)
{
case TypeCode.Boolean:
WriteFieldHeader(ti, tag);
writer.Write((byte)(((bool)value)?1:0));
break;
case TypeCode.Byte:
WriteFieldHeader(ti, tag);
writer.Write((byte)value);
break;
case TypeCode.SByte:
WriteFieldHeader(ti, tag);
writer.Write((sbyte)value);
break;
case TypeCode.Char:
case TypeCode.Int16:
case TypeCode.UInt16:
case TypeCode.Int32:
WriteFieldHeader(ti, tag);
writer.Write((Int32)value);
break;
case TypeCode.UInt32:
WriteFieldHeader(ti, tag);
writer.Write((UInt32)value);
break;
case TypeCode.Int64:
WriteFieldHeader(ti, tag);
writer.Write((Int64)value);
break;
case TypeCode.UInt64:
WriteFieldHeader(ti, tag);
writer.Write((UInt64)value);
break;
case TypeCode.Double:
WriteFieldHeader(ti, tag);
writer.Write((double)value);
break;
case TypeCode.Single:
WriteFieldHeader(ti, tag);
writer.Write((float)value);
break;
case TypeCode.String:
WriteFieldHeader(ti, tag);
WriteString((string)value);
break;
case TypeCode.Object:
{
if (type.IsGenericType)
{
if (type.GetGenericTypeDefinition() ==typeof(List<>) || type.GetGenericTypeDefinition() ==typeof(LinkedList<>))
{
WriteFieldHeader(ti, tag);
if (value ==null)
{
writer.Write((int)-1);
}
else
{
int count = (int)value.GetType().GetProperty("Count").GetValue(value,null);
Type elementType = value.GetType().GetGenericArguments()[0];
writer.Write(count);
System.Collections.IEnumerable enumerable = valueas System.Collections.IEnumerable;
foreach (object oin enumerable)
{
SerializeCore(o, elementType,tag);
}
}
}
else if (type.GetGenericTypeDefinition() == typeof(Dictionary<,>) || type.GetGenericTypeDefinition() ==typeof(SortedDictionary<,>))
{
WriteFieldHeader(ti, tag);
if (value !=null)
{
int count = (int)value.GetType().GetProperty("Count").GetValue(value,null);
Type elementKeyType = value.GetType().GetGenericArguments()[0];
Type elementValueType = value.GetType().GetGenericArguments()[1];
writer.Write(count);
System.Collections.IEnumerable enumerable = valueas System.Collections.IEnumerable;
foreach (object oin enumerable)
{
var itemKey = o.GetType().GetProperty("Key").GetValue(o,null);
var itemValue = o.GetType().GetProperty("Value").GetValue(o,null);
SerializeCore(itemKey, elementKeyType,1);
SerializeCore(itemValue,elementValueType, 2);
}
}
else
{
writer.Write(-1);
}
}
}
else if (type.IsArray)
{
WriteFieldHeader(ti, tag);
if (value==null)
{
writer.Write((int)-1);
}
else
{
Array array = (Array)value;
writer.Write(array.Length);
//Core.Logger.LogInfo("save array:" + array.Length);
for (int i = 0; i < array.Length; i++)
SerializeCore(array.GetValue(i), type.GetElementType(),tag);
}
}
else if (type.IsEnum)
{
//int32
WriteFieldHeader(ti, tag);
writer.Write((int)value);
}
else if ((type.IsValueType && !type.IsPrimitive) || type.IsClass)
{
SerializeObject(value, tag);
}
}
break;
default:
break;
}
}
(反序列化)
protected virtual object DeserializeObject(object value,Type type, TagType tag)
{
TypeIndex obj_ti;
TagType obj_tag;
ReadFieldHeader(out obj_tag,out obj_ti);
//引用对象
Asset(TypeIndex.RefObject == obj_ti ||TypeIndex.Object == obj_ti);
if (obj_ti == TypeIndex.RefObject)
{
return DeserializeRefObject();
}
int count = reader.ReadInt32();
if(count == -1)
{
return null;
}
if(count == 0)
{
throw new Exception(string.Format("{0}对象序列化格式错误 count==0缺失类型", value.GetType().Name));
}
//类型
{
TypeIndex field_ti;
TagType field_tag;
ReadFieldHeader(out field_tag,out field_ti);
Asset(field_ti == TypeIndex.Custom);
type = ReadType(type);
}
//自定义数据
{
TypeIndex field_ti;
TagType field_tag;
ReadFieldHeader(out field_tag,out field_ti);
Asset(field_ti == TypeIndex.Custom);
ReadObjectCustomData(ref value,type,tag);
}
if (value == null)
{
value = Activator.CreateInstance(type);
}
//对象保存
if(IsReferenceType(type))
Objects.Add(value);
Dictionary<int,Type> Types =new Dictionary<int,Type>();
Type baseType = value.GetType();
while (baseType != null)
{
ContractAttribute ca =CompatibleAPI.GetCustomAttribute<ContractAttribute>(baseType);
if (ca != null)
{
Types.Add(ca.Tag,baseType);
baseType = baseType.BaseType;
}
else
{
break;
}
}
if (Types.Count == 0)
{
throw new Exception(string.Format("要序列化的类型 {0}没有标记序列化属性Contract", value.GetType().Name));
}
for (int i=0;i<count-2;i++)
{
TypeIndex field_ti;
TagType field_tag;
LookFieldHeader(out field_tag,out field_ti);
if(Types.ContainsKey(field_tag))
{
DeserializeObjectTyped(value, Types[field_tag], field_tag);
}
else
{
SkipField();
}
}
return value;
}
object DeserializeObjectTyped(object obj,Type type, int tag)
{
TypeIndex obj_ti;
TagType obj_tag;
ReadFieldHeader(out obj_tag,out obj_ti);
int count = reader.ReadInt32();
Dictionary<int,FieldInfo> fieldDic = new Dictionary<int,FieldInfo>();
FieldInfo[] fi = type.GetFields(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public |BindingFlags.NonPublic);
foreach (var vin fi)
{
if(v.DeclaringType == type)
{
MemberAttribute attr =CompatibleAPI.GetCustomAttribute<MemberAttribute>(v);
if (attr != null && IsSupportedField(v, attr))
{
fieldDic.Add(attr.Tag, v);
}
}
}
for (int i = 0; i < count; i++)
{
TypeIndex field_ti;
TagType field_tag;
LookFieldHeader(out field_tag,out field_ti);
FieldInfo fieldInfo =null;
if (fieldDic.TryGetValue(field_tag,out fieldInfo))
{
fieldInfo.SetValue(obj, DeserializeCore(fieldInfo.FieldType, field_tag));
}
else
{
SkipField();
}
}
return obj;
}
void Asset(bool trueValue)
{
if(!trueValue)
{
throw new ArgumentException("Asset");
}
}
object DeserializeCore(Type type,TagType fieldNumber)
{
TypeCode tc = Type.GetTypeCode(type);
if (type.IsEnum)
{
TypeIndex ti;
TagType tag;
ReadFieldHeader(out tag,out ti);
Asset(GetWireTypeIndex(type) == ti);
int v = reader.ReadInt32();
return Enum.Parse(type, v.ToString());
}
switch (tc)
{
case TypeCode.Boolean:
{
TypeIndex ti;
TagType tag;
ReadFieldHeader(out tag,out ti);
Asset(GetWireTypeIndex(type) == ti);
return reader.ReadByte()!=0?true:false;
}
case TypeCode.Byte:
{
TypeIndex ti;
TagType tag;
ReadFieldHeader(out tag,out ti);
Asset(GetWireTypeIndex(type) == ti);
return reader.ReadByte();
}
case TypeCode.SByte:
{
TypeIndex ti;
TagType tag;
ReadFieldHeader(out tag,out ti);
Asset(GetWireTypeIndex(type) == ti);
return reader.ReadSByte();
}
case TypeCode.Char:
case TypeCode.Int16:
case TypeCode.UInt16:
case TypeCode.Int32:
{
TypeIndex ti;
TagType tag;
ReadFieldHeader(out tag,out ti);
Asset(GetWireTypeIndex(type) == ti);
return Convert.ChangeType( reader.ReadInt32(),type);
}
case TypeCode.UInt32:
{
TypeIndex ti;
TagType tag;
ReadFieldHeader(out tag,out ti);
Asset(GetWireTypeIndex(type) == ti);
return reader.ReadUInt32();
}
case TypeCode.Int64:
{
TypeIndex ti;
TagType tag;
ReadFieldHeader(out tag,out ti);
Asset(GetWireTypeIndex(type) == ti);
return reader.ReadInt64();
}
case TypeCode.UInt64:
{
TypeIndex ti;
TagType tag;
ReadFieldHeader(out tag,out ti);
Asset(GetWireTypeIndex(type) == ti);
return reader.ReadUInt64();
}
case TypeCode.Double:
{
TypeIndex ti;
TagType tag;
ReadFieldHeader(out tag,out ti);
Asset(GetWireTypeIndex(type) == ti);
return reader.ReadDouble();
}
case TypeCode.Single:
{
TypeIndex ti;
TagType tag;
ReadFieldHeader(out tag,out ti);
Asset(GetWireTypeIndex(type) == ti);
return reader.ReadSingle();
}
case TypeCode.String:
{
TypeIndex ti;
TagType tag;
ReadFieldHeader(out tag,out ti);
Asset(GetWireTypeIndex(type) == ti);
return ReadString();
}
case TypeCode.Object:
{
if (type.IsGenericType)
{
if (type.GetGenericTypeDefinition() ==typeof(List<>) || type.GetGenericTypeDefinition() ==typeof(LinkedList<>))
{
TypeIndex ti;
TagType tag;
ReadFieldHeader(out tag,out ti);
Asset(GetWireTypeIndex(type) == ti);
int count = reader.ReadInt32();
if (count == -1)
returnnull;
Type elementType = type.GetGenericArguments()[0];
MethodInfo method =null;
if (type.GetGenericTypeDefinition() ==typeof(List<>))
method = type.GetMethod("Add",new Type[] { elementType });
else
method = type.GetMethod("AddLast",new Type[] { elementType });
object f =Activator.CreateInstance(type);
for (int i = 0; i < count; i++)
{
object v = DeserializeCore(elementType, tag);
method.Invoke(f, new object[] { v });
}
return f;
}
else if (type.GetGenericTypeDefinition() == typeof(Dictionary<,>) || type.GetGenericTypeDefinition() ==typeof(SortedDictionary<,>))
{
TypeIndex ti;
TagType tag;
ReadFieldHeader(out tag,out ti);
Asset(GetWireTypeIndex(type) == ti);
int count = reader.ReadInt32();
if (count == -1)
returnnull;
object f =Activator.CreateInstance(type);
Type elementKeyType = f.GetType().GetGenericArguments()[0];
Type elementValueType = f.GetType().GetGenericArguments()[1];
for (int i = 0; i < count; i++)
{
object key = DeserializeCore(elementKeyType, 1);
object value = DeserializeCore(elementValueType, 2);
f.GetType().GetMethod("Add").Invoke(f,new object[] { key, value });
}
return f;
}
}
else if (type.IsArray)
{
TypeIndex ti;
TagType tag;
ReadFieldHeader(out tag,out ti);
Asset(GetWireTypeIndex(type) == ti);
int count = reader.ReadInt32();
if (count == -1)
returnnull;
Type elementType = type.GetElementType();
Array v =Array.CreateInstance(elementType, count);
//Core.Logger.LogInfo("read array:" + count);
for (int i=0;i<count;i++)
{
v.SetValue(DeserializeCore(elementType,tag), i);
}
return v;
}
else if (type.IsEnum)
{
TypeIndex ti;
TagType tag;
ReadFieldHeader(out tag,out ti);
Asset(GetWireTypeIndex(type) == ti);
returnConvert.ChangeType( reader.ReadInt32(),type);
}
else if ((type.IsValueType && !type.IsPrimitive) || type.IsClass)
{
return DeserializeObject(null, type, fieldNumber);
}
}
break;
default:
break;
}
return SkipField();
}
- 模仿protobuf的对象序列化系统
- protobuf对象二进制序列化存储
- C#使用Protocol Buffer(ProtoBuf)进行对象的序列化与反序列化
- Netty集成Google的ProtoBuf序列化
- Beetle使用Protobuf.net进行对象序列化传输
- Simple-Spring-Memcached使用Protobuf序列化Java对象
- 手工使用Protobuf-net工具来序列化对象
- Protobuf序列化协议
- protobuf序列化存储
- protobuf (序列化协议)
- 序列化protobuf
- protobuf序列化原理
- Jackson--protobuf序列化积累
- C# Protobuf-Net 序列化
- google protobuf序列化原理
- Python 序列化之 ProtoBuf
- Protobuf 序列化协议详解
- google protobuf序列化原理
- 网上图片本地保存并进行压缩操作
- gdfzoj #547 diaosi(dp)
- 关于Hibernate5的自定义会话工厂
- Problem D: 从点到面
- BaseActivity集成的功能方法,总有一个是你需要的
- 模仿protobuf的对象序列化系统
- 剑指offer-35.数组中的逆序对
- 表达式求值 第九届河南省赛
- HEVC解码器HM源码阅读(二)解码器中类的介绍
- Map集合
- STL find 函数
- ACM卡常数
- Eclipse 快捷键备忘
- SqlSessionFactoryUtil