代码自动生成工具(二)-miniproto的c#库实现


本项目暂命名miniproto1.0。

有限的兼容protobuf的语法规则 和 编码规则。包括protobuf2.0和3.0的编码规则。

实现proto结构的序列化、反序列化功能。

代码生成工具,需要boost库支持(主要用了spirit库做文本解析),本人用的是boost.1.64.0。

生成后的代码,仅需要miniproto自身提供的lib(对应c++)、dll(对应c#)、jar(对应java),不需要其他第三方库。

完整项目下载地址(项目为vs2017建立的,boost库路径请自行配置)

Github项目地址



前文介绍了miniproto,这里介绍其c#库的实现。

Zigzag编码和Varint编码就不再赘述,可以参考miniproto的c++库实现。

1、委托

容器元素的编解码,用到了c#的委托。类似于c的函数指针的一个东西。

委托这个东西本文就不具体介绍了,网上很多深入浅出的文章说明。

这里说下为什么会用到委托:主要是因为c#的泛型,并不存在c++中的模板参数自动推导机制。比如:

		static void FunA(int t)
		{}
		static void FunA(long t)
		{}
		static void FunB<T>(T t)
		{
			FunA(t); // 此处c#编译是通不过的
		}

这样的代码在c++中是没有问题的,编译器会根据 实际调用FunB的地方传递的实参类型来判断形参T是什么类型,进而去调用更匹配的FunA的重载。

但是c#没有这样的机制,这样写编译是通不过的。用委托能相对来说比较优雅的解决这个需求(参考这篇文章)。如下:

		delegate void Call<T>(T value);
		private static class Function<T>
		{
			public static Call<T> call;
		}
		static void FunA(int t)
		{}
		static void FunA(long t)
		{}
		static void FunB<T>(T t)
		{
			Function<T>.call(t);
		}
		static void Main(string[] args)
		{
			Function<int>.call = (int value) => FunA(value);
			Function<long>.call = (long value) => FunA(value);
			FunB<int>(1);
			FunB<long>(1L);
		}

2、ProtoTool

基本雷同C++的ProtoTool,前半部分基本相同,后半部分容器的编解码用到委托。针对不同数据类型,给出一系列的编解码功能实现。

下面给出ProtoTool代码,对照代码做出注释说明。具体实现就不贴了,可以去下载完整项目。

// proto字段编码工具类
public static class ProtoTool
{
	// Zigzag编/解码
	public static uint Zigzag(int value);
	public static ulong Zigzag(long value);
	public static int DeZigzag(uint value);
	public static long DeZigzag(ulong value);

	// Varint/fixed32/fixed64 编/解码
	public static ulong NumberByteSize(uint value);
	public static ulong NumberByteSize(ulong value);
	public static ulong NumberByteSize(float value);
	public static ulong NumberByteSize(double value);
	public static ulong NumberCode(uint value, Stream buf);
	public static ulong NumberCode(ulong value, Stream buf);
	public static ulong NumberCode(float value, Stream buf);
	public static ulong NumberCode(double value, Stream buf);
	public static ulong NumberDecode(ref uint value, Stream buf);
	public static ulong NumberDecode(ref ulong value, Stream buf);
	public static ulong NumberDecode(ref float value, Stream buf);
	public static ulong NumberDecode(ref double value, Stream buf);

	// proto key编/解码,即对 (字段Tag << 3 + 字段WiteType) 做varint编/解码
	public static ulong KeyByteSize(uint num, uint type);
	public static ulong KeyCode(uint num, uint type, Stream buf);
	public static ulong KeyDecode(ref uint num, ref uint type, Stream buf);
           
	// 未知字段解码  
	// 如果出现未定义的tag字段时,对该字段的编解码  
	// 如果出现不支持的WiteType,抛UnknownWireTypeException
	public static ulong UnknownDecode(uint type, Stream buf);

	// 单个字段编/解码
	public static ulong BoolByteSize(bool value);
	public static ulong BoolCode(bool value, Stream buf);
	public static ulong BoolDecode(ref bool value, Stream buf);

	public static ulong Int32ByteSize(int value);
	public static ulong Int32Code(int value, Stream buf);
	public static ulong Int32Decode(ref int value, Stream buf);

	public static ulong Int64ByteSize(long value);
	public static ulong Int64Code(long value, Stream buf);
	public static ulong Int64Decode(ref long value, Stream buf);

	public static ulong SInt32ByteSize(int value);
	public static ulong SInt32Code(int value, Stream buf);
	public static ulong SInt32Decode(ref int value, Stream buf);

	public static ulong SInt64ByteSize(long value);
	public static ulong SInt64Code(long value, Stream buf);
	public static ulong SInt64Decode(ref long value, Stream buf);

	public static ulong UInt32ByteSize(uint value);
	public static ulong UInt32Code(uint value, Stream buf);
	public static ulong UInt32Decode(ref uint value, Stream buf);

	public static ulong UInt64ByteSize(ulong value);
	public static ulong UInt64Code(ulong value, Stream buf);
	public static ulong UInt64Decode(ref ulong value, Stream buf);

	public static ulong EnumByteSize<E>(E value);
	public static ulong EnumCode<E>(E value, Stream buf);
	public static ulong EnumDecode<E>(ref E value, Stream buf);

	public static ulong FloatByteSize(float value);
	public static ulong FloatCode(float value, Stream buf);
	public static ulong FloatDecode(ref float value, Stream buf);

	public static ulong DoubleByteSize(double value);
	public static ulong DoubleCode(double value, Stream buf);
	public static ulong DoubleDecode(ref double value, Stream buf);

	public static ulong StringByteSize(string value);
	public static ulong StringCode(string value, Stream buf);
	public static ulong StringDecode(ref string value, Stream buf);

	public static ulong MessageByteSize<M>(M value) where M : ProtoBase;
	public static ulong MessageCode<M>(M value, Stream buf) where M : ProtoBase;
	public static ulong MessageDecode<M>(ref M value, Stream buf) where M : ProtoBase;

	// 针对不同数据类型的编/解码函数的委托
	// 利用模板对应 具体数据类型 以及其对应的ByteSize/Code/Decode处理函数
	delegate TResult FunByteSize<T, TResult>(T value);
	delegate TResult FunCode<T, TResult>(T value, Stream buf);
	delegate TResult FunDecode<T, TResult>(ref T value, Stream buf);

	private static class Cache<T, P>
	{
		public static FunByteSize<T, ulong> ByteSize;
		public static FunCode<T, ulong> Code;
		public static FunDecode<T, ulong> Decode;
	}

	// 初始化,注册具体类型T对应的ByteSize/Code/Decode委托函数
	// 对于自定义枚举类型,实际逻辑处理时,现用现注册委托函数
	static ProtoTool();

	// Array,Set容器中,每一个元素的编/解码
	private static ulong EntryByteSize<T, P>(T value, P type);
	private static ulong EntryCode<T, P>(T value, Stream buf, P type);
	private static ulong EntryDecode<T, P>(ref T value, Stream buf, P type);

	// Array容器的编/解码
	// 内部调用EntryByteSize/Code/Decode
	private static ulong ArrayByteSizeWithoutLength<T, P>(IList<T> values, P type);
	public static ulong ArrayByteSize<T, P>(IList<T> values, P type);
	public static ulong ArrayCode<T, P>(IList<T> values, Stream buf, P type);
	public static ulong ArrayDecode<T, P>(IList<T> values, Stream buf, P type);

	// Array容器中元素为的ProtoBase时的编/解码
	// 由于需要调用ProtoBase的接口,所以T必须做约束,单独做重载
	// 内部调用EntryByteSize/Code/Decode
	private static ulong ArrayByteSizeWithoutLength<T>(IList<T> values) where T : ProtoBase;
	public static ulong ArrayByteSize<T>(IList<T> values) where T : ProtoBase;
	public static ulong ArrayCode<T>(IList<T> values, Stream buf) where T : ProtoBase;
	public static ulong ArrayDecode<T>(IList<T> values, Stream buf) where T : ProtoBase, new();

	// Set容器的编/解码
	// 内部调用EntryByteSize/Code/Decode
	private static ulong SetByteSizeWithoutLength<T, P>(ISet<T> values, P type);
	public static ulong SetByteSize<T, P>(ISet<T> values, P type);
	public static ulong SetCode<T, P>(ISet<T> values, Stream buf, P type);
	public static ulong SetDecode<T, P>(ISet<T> values, Stream buf, P type);


	// Map容器中,每一个元素的编/解码
	private static ulong EntryByteSizeWithoutLength<K, V, KP, VP>(K key, V value, KP keyType, VP valueType) where KP : ProtoType where VP : ProtoType;
	public static ulong EntryByteSize<K, V, KP, VP>(K key, V value, KP keyType, VP valueType) where KP : ProtoType where VP : ProtoType;
	public static ulong EntryCode<K, V, KP, VP>(K key, V value, Stream buf, KP keyType, VP valueType) where KP : ProtoType where VP : ProtoType;
	public static ulong EntryDecode<K, V, KP, VP>(ref K key, ref V value, Stream buf, KP keyType, VP valueType) where KP : ProtoType where VP : ProtoType;

	// Map容器中元素为的ProtoBase时,每一个元素的编/解码
	// 由于需要调用ProtoBase的接口,所以V必须做约束,单独做重载
	private static ulong EntryByteSizeWithoutLength<K, V, KP>(K key, V value, KP keyType) where V : ProtoBase where KP : ProtoType;
	public static ulong EntryByteSize<K, V, KP>(K key, V value, KP keyType) where V : ProtoBase where KP : ProtoType;
	public static ulong EntryCode<K, V, KP>(K key, V value, Stream buf, KP keyType) where V : ProtoBase where KP : ProtoType;
	public static ulong EntryDecode<K, V, KP>(ref K key, ref V value, Stream buf, KP keyType) where V : ProtoBase where KP : ProtoType;

	// Map容器的编/解码
	// 内部调用EntryByteSize/Code/Decode
	private static ulong DictionaryByteSizeWithoutLength<K, V, KP, VP>(IDictionary<K, V> values, KP keyType, VP valueType) where KP : ProtoType where VP : ProtoType;
	public static ulong DictionaryByteSize<K, V, KP, VP>(IDictionary<K, V> values, KP keyType, VP valueType) where KP : ProtoType where VP : ProtoType;
	public static ulong DictionaryCode<K, V, KP, VP>(IDictionary<K, V> values, Stream buf, KP keyType, VP valueType) where KP : ProtoType where VP : ProtoType;
	public static ulong DictionaryDecode<K, V, KP, VP>(IDictionary<K, V> values, Stream buf, KP keyType, VP valueType) where KP : ProtoType where VP : ProtoType;

	// Map容器中元素为的ProtoBase时的编/解码
	// 由于需要调用ProtoBase的接口,所以V必须做约束,单独做重载
	// 内部调用EntryByteSize/Code/Decode
	private static ulong DictionaryByteSizeWithoutLength<K, V, KP>(IDictionary<K, V> values, KP keyType) where V : ProtoBase where KP : ProtoType;
	public static ulong DictionaryByteSize<K, V, KP>(IDictionary<K, V> values, KP keyType) where V : ProtoBase where KP : ProtoType;
	public static ulong DictionaryCode<K, V, KP>(IDictionary<K, V> values, Stream buf, KP keyType) where V : ProtoBase where KP : ProtoType;
	public static ulong DictionaryDecode<K, V, KP>(IDictionary<K, V> values, Stream buf, KP keyType) where V : ProtoBase where KP : ProtoType;
}

3、ProtoBase

基本雷同C++的ProtoBase,只是没有了 序列化/反序列化 到 char *buf 内存,因为都是Stream流。

// 所有自定义message的基类
public abstract class ProtoBase
{
	public ProtoBase();

	public abstract ulong ByteSize();
	public abstract ulong Code(Stream buf, ulong size);
	public abstract ulong Decode(Stream buf, ulong size);

	public abstract void Clear();
	public abstract void Release();

	public bool SerializeToStream(Stream buf, ulong size);
	public bool ParseFromStream(Stream buf, ulong size);
};

4、ProtoBitMap

基本雷同c++的ProtoBitMap,除掉这里没法把位图长度作为模板参数,因此只能作为构造函数的参数

public class ProtoBitMap
{
	public ProtoBitMap(uint count);
	public void SetBit(uint index);
	public void ClearBit(uint index);
	public bool HasBit(uint index);
	public void Clear();

	private byte[] m_Bits = null;
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值