最新文章
泰课新年学课蛇来运转欢度春节活动
02-01 20:25
共庆2024圣诞、元旦泰课双蛋活动
12-16 10:21
泰课共庆75周年国庆活动!
10-05 21:24
暑假双月联动学习计划 7月15 - 8月21日
07-14 23:09
泰课在线劳动光荣,勤学快乐之五月勤学季活动
04-30 21:19
2024年青春绽放开学季活动
03-11 13:01
Protobuf :repeated类型的使用
在Protobuf(Protocol Buffers)中,repeated 类型类似于C++中的 std::vector 或 std::list,可以将其理解为指定类型的数组。下面将详细介绍 repeated 类型的使用。
定义Protobuf结构
首先,我们定义一个Protobuf消息结构,以 Actor_GamerEnterRoom_Ntt 消息为例,它用于广播玩家进入房间的信息,代码如下:
// 进入房间(广播)
message Actor_GamerEnterRoom_Ntt { // IActorMessage
int32 RpcId = 90;
int64 ActorId = 93;
repeated GamerInfo Gamers = 1;
}
在上述代码中,repeated GamerInfo Gamers = 1; 表示 Gamers 是一个 GamerInfo 类型的数组,可以包含零个或多个 GamerInfo 元素。
repeated 类型的使用示例
下面通过一个具体的代码示例,展示如何在程序中使用这个Protobuf消息结构:
public partial class Actor_GamerEnterRoom_Ntt : pb::IMessage
{
// 消息解析器,使用消息池获取实例
private static readonly pb::MessageParser<Actor_GamerEnterRoom_Ntt> _parser = new pb::MessageParser<Actor_GamerEnterRoom_Ntt>(() => (Actor_GamerEnterRoom_Ntt)MessagePool.Instance.Fetch(typeof(Actor_GamerEnterRoom_Ntt)));
public static pb::MessageParser<Actor_GamerEnterRoom_Ntt> Parser
{
get { return _parser; }
}
// RpcId字段的私有成员变量和属性
private int rpcId_;
public int RpcId
{
get { return rpcId_; }
set { rpcId_ = value; }
}
// ActorId字段的私有成员变量和属性
private long actorId_;
public long ActorId
{
get { return actorId_; }
set { actorId_ = value; }
}
// 用于编码和解码Gamers字段的编解码器
private static readonly pb::FieldCodec<global::ETModel.GamerInfo> _repeated_gamers_codec = pb::FieldCodec.ForMessage(10, global::ETModel.GamerInfo.Parser);
// 存储Gamers字段的重复字段
private pbc::RepeatedField<global::ETModel.GamerInfo> gamers_ = new pbc::RepeatedField<global::ETModel.GamerInfo>();
public pbc::RepeatedField<global::ETModel.GamerInfo> Gamers
{
get { return gamers_; }
set { gamers_ = value; }
}
// 将消息写入输出流
public void WriteTo(pb::CodedOutputStream output)
{
// 写入Gamers字段
gamers_.WriteTo(output, _repeated_gamers_codec);
// 如果RpcId不为0,写入RpcId字段
if (RpcId != 0)
{
output.WriteRawTag(208, 5);
output.WriteInt32(RpcId);
}
// 如果ActorId不为0,写入ActorId字段
if (ActorId != 0L)
{
output.WriteRawTag(232, 5);
output.WriteInt64(ActorId);
}
}
// 计算消息的字节大小
public int CalculateSize()
{
int size = 0;
// 如果RpcId不为0,计算RpcId字段的大小
if (RpcId != 0)
{
size += 2 + pb::CodedOutputStream.ComputeInt32Size(RpcId);
}
// 如果ActorId不为0,计算ActorId字段的大小
if (ActorId != 0L)
{
size += 2 + pb::CodedOutputStream.ComputeInt64Size(ActorId);
}
// 计算Gamers字段的大小
size += gamers_.CalculateSize(_repeated_gamers_codec);
return size;
}
// 从输入流中合并消息
public void MergeFrom(pb::CodedInputStream input)
{
// 回收Gamers字段中的所有元素
for (int i = 0; i < gamers_.Count; i++)
{
MessagePool.Instance.Recycle(gamers_[i]);
}
// 清空Gamers字段
gamers_.Clear();
// 重置RpcId和ActorId字段
rpcId_ = 0;
actorId_ = 0;
uint tag;
// 读取输入流中的标签
while ((tag = input.ReadTag()) != 0)
{
switch (tag)
{
default:
// 跳过未知字段
input.SkipLastField();
break;
case 10:
// 从输入流中添加Gamers字段的元素
gamers_.AddEntriesFrom(input, _repeated_gamers_codec);
break;
case 720:
// 读取RpcId字段
RpcId = input.ReadInt32();
break;
case 744:
// 读取ActorId字段
ActorId = input.ReadInt64();
break;
}
}
}
}
代码解释
- 消息解析器:
_parser用于解析Actor_GamerEnterRoom_Ntt消息,通过消息池获取实例,提高性能。 - 字段属性:
RpcId和ActorId是普通的整型字段,提供了对应的属性访问器。 repeated字段:Gamers是一个repeated字段,使用pbc::RepeatedField<global::ETModel.GamerInfo>存储,提供了对应的属性访问器。- 写入消息:
WriteTo方法将消息写入输出流,包括Gamers、RpcId和ActorId字段。 - 计算大小:
CalculateSize方法计算消息的字节大小,包括所有字段的大小。 - 合并消息:
MergeFrom方法从输入流中读取消息,并合并到当前实例中,同时处理repeated字段的元素。
通过以上步骤,我们可以在程序中使用Protobuf的 repeated 类型,实现高效的数据传输和处理。