using System; using System.Collections.Generic; namespace ProtoCSStruct { public class ProtoMessage { //字节对齐,4字节或8字节 public int AlignByte; //结构体在内存里大小 private int SizeOf = int.MaxValue; //是否是需要unsafe 修饰 public bool Unsafe; public string Name; public List Fields = new List(); public Dictionary FieldsMap = new Dictionary(); public int GetMessageSize() { if(SizeOf == int.MaxValue) { Calc(); } return SizeOf; } public void Calc() { if (SizeOf != int.MaxValue) { return; } CalcStructSize(); CalcUnsafe(); } //结构体的大小,字节对齐 //结构体的大小其实算错了不要紧,只要算出来不比实际小就没问题 private void CalcStructSize() { //缺省8字节对齐 //往大了对齐肯定不会有错就是了 //要不然还要递归算,子结构体如果8字节对齐,那么此结构也8字节对齐 //所以全都8字节对齐算了,无非浪费点内存 AlignByte = 8; //如果有int64和uint64,则8字节对齐 /* foreach(var field in Fields) { if(field.IsRepeated) { continue; } if(field.FieldType == FieldType.Int64 || field.FieldType == FieldType.UInt64) { AlignByte = 8; break; } }*/ int sizeOffset = 0; int calcSize = 0; //根据对齐,字段大小 foreach (var field in Fields) { int fieldSize = 0; int multiply = 1; if (field.IsRepeated || field.FieldType == FieldType.Bytes) { multiply = field.RepeatedCount; } if (field.FieldType == FieldType.Bool || field.FieldType == FieldType.Bytes) { fieldSize = 1; } else if (field.FieldType == FieldType.Int32 || field.FieldType == FieldType.UInt32 || field.FieldType == FieldType.Enum) { fieldSize = 4; if(sizeOffset % 4 != 0) { sizeOffset += (4 - (sizeOffset % 4)); } } else if (field.FieldType == FieldType.Int64 || field.FieldType == FieldType.UInt64) { fieldSize = 8; if (sizeOffset % 8 != 0) { sizeOffset += (8 - (sizeOffset % 8)); } } else if (field.FieldType == FieldType.String) { fieldSize = field.StringLength * 2 + AlignByte; } else if (field.FieldType == FieldType.Message) { fieldSize = field.Message.GetMessageSize(); } fieldSize = fieldSize * multiply; if (field.IsRepeated || field.FieldType == FieldType.Bytes) { field.RepeatedFiledBuffSize = fieldSize; if (field.RepeatedFiledBuffSize % AlignByte != 0) //补齐 { field.RepeatedFiledBuffSize += (AlignByte - (field.RepeatedFiledBuffSize % AlignByte)); } fieldSize = field.RepeatedFiledBuffSize + AlignByte; } sizeOffset += fieldSize; while (sizeOffset > AlignByte) { calcSize += AlignByte; sizeOffset -= AlignByte; } } if(sizeOffset > 0) { calcSize += AlignByte; sizeOffset = 0; } //只有空结构体,算出来才是0 if(calcSize == 0) { SizeOf = AlignByte; } else { SizeOf = calcSize; } } //是否需要unsafe修饰 private void CalcUnsafe() { Unsafe = false; /* foreach (var field in Fields) { if(field.FieldType == FieldType.Bytes) { Unsafe = true; return; } if (field.IsRepeated) { if (field.FieldType != FieldType.String && field.FieldType != FieldType.Message) { Unsafe = true; return; } } } */ } } }