带有扩展的协议缓冲区
-
16-09-2019 - |
题
我也许正在忽略某些东西,但是我正在尝试将协议缓冲区搏斗到以后提供扩展的一种简单方法中。这似乎有点不清楚,所以我将直接陷入问题。
我正在编写一个组件来支持各种任务,其中之一包括描述结构化数据。使用协议缓冲区的最佳时机。使用协议缓冲区的主要类称为“表示定义”。这是我想出的.proto文件:
package Kannon.State; message StateDefinition { enum StateTypes { GRAPHICS = 0; AUDIO = 1; MIND = 2; PHYSICS = 3; NETWORK = 4; GENERIC = 5; } repeated StateTypes requiredStates = 1; optional GraphicsStateDef Graphics = 2; optional AudioStateDef Audio = 3; (etc) } message GraphicsStateDef { extensions 100 to max; } message AudioStateDef { extensions 100 to max; } (etc)
我的目标是允许以后使用所需的字段扩展那些_StatedEF消息。但是,此扩展名将独立于我目前正在编写的库中。
kagents.dll->处理说明的解析等。
引用kagents.dll->具有带有“扩展GraphicsStatedEf”的原子文件以定义所需状态。
我希望定义“扩展GraphicsStatedEf”能够生成代码,使我能够使用属性访问这些字段,并避免繁琐的“ Extendible.AppendValue()”和GetValue()语法。
我设计的一种解决方案似乎是hackish,是用扩展方法定义引用DLL中的类,例如:
public static class GraphicsExt { enum Fields { someValue = 1, someOtherValue = 2 } public static Int32 someValue(this State.GraphicsStateDef def) { return Extensible.GetValue(def, Fields.someValue); } public static void someValue(this State.graphicsStateDef def, Int32 value) { Extensible.AppendValue(def, fields.someValue, value); } }
如果有人能想到更好的方法,我将是很多义务。 =)另外,我不确定我对问题的描述有多清醒,因此,如果我可以提供任何澄清或更多信息,请告诉我。 =)
编辑:因此,在考虑了很多事情之后,意识到我将问题错误。 StateReference应该存储不同游戏的列表。同样,它存储了一个陈述的定义,该定义应描述该状态参考的状态。当前,我正在尝试将状态缓冲区置于不同的类(GraphicsStatedEF)中,而我确实应该对状态对象本身进行挑选。
因此,我需要重新考虑设计,以使陈述的定义成为流的容器,并仅提取足够的信息,以供“重复的Statepes quirces usirdeDSTATES = 1”字段提取。然后,在引用组件中,其余的流可以被划分到各个状态中。
有人对如何处理有裁员吗?一些想法正在制定,但没有任何具体的想法,我会喜欢别人的意见。
解决方案 2
最终答案:
好吧,所以,几天前,我解决了一个解决方案,如果其他人遇到同一问题,我只是在更新它。
整个问题源于我没有意识到Protobuf-net可以支持字节[]的事实。所以,这是我的解决方案:
namespace Kannon.State
{
/// <summary>
/// ReferenceDefinition describes the layout of the reference in general.
/// It tells what states it should have, and stores the stream buffers for later serialization.
/// </summary>
[ProtoBuf.ProtoContract]
public class ReferenceDefinition
{
/// <summary>
/// There are several built in state types, as well as rudimentary support for a "Generic" state.
/// </summary>
public enum StateType
{
Graphics=0,
Audio,
Mind,
Physics,
Network,
Generic
}
/// <summary>
/// Represents what states should be present in the ReferenceDefinition
/// </summary>
[ProtoBuf.ProtoMember(1)]
List<StateType> m_StatesPresent = new List<StateType>();
/// <summary>
/// Represent a list of StateDefinitions, which hold the buffers for each different type of state.
/// </summary>
[ProtoBuf.ProtoMember(2)]
List<StateDefinition> m_StateDefinition = new List<StateDefinition>();
/// <summary>
/// Add a state, mapped to a type, to this reference definition.
/// </summary>
/// <param name="type">Type of state to add</param>
/// <param name="def">State definition to add.</param>
public void AddState(StateType type, StateDefinition def)
{
// Enforce only 1 of each type, except for Generic, which can have as many as it wants.
if (m_StatesPresent.Contains(type) && type != StateType.Generic)
return;
m_StatesPresent.Add(type);
m_StateDefinition.Add(def);
}
}
/// <summary>
/// Represents a definition of some gamestate, storing protobuffered data to be remapped to the state.
/// </summary>
[ProtoBuf.ProtoContract]
public class StateDefinition
{
/// <summary>
/// Name of the state
/// </summary>
[ProtoBuf.ProtoMember(1)]
string m_StateName;
/// <summary>
/// Byte array to store the "data" for later serialization.
/// </summary>
[ProtoBuf.ProtoMember(2)]
byte[] m_Buffer;
/// <summary>
/// Constructor for the state definition, protected to enforce the Pack and Unpack functionality to keep things safe.
/// </summary>
/// <param name="name">Name of the state type.</param>
/// <param name="buff">byte buffer to build state off of</param>
protected StateDefinition(String name, byte[] buff)
{
m_StateName = name;
m_Buffer = buff;
}
/// <summary>
/// Unpack a StateDefinition into a GameState
/// </summary>
/// <typeparam name="T">Gamestate type to unpack into. Must define Protobuf Contracts.</typeparam>
/// <param name="def">State Definition to unpack.</param>
/// <returns>The unpacked state data.</returns>
public static T Unpack<T>(StateDefinition def) where T:GameState
{
// Make sure we're unpacking into the right state type.
if (typeof(T).Name == def.m_StateName)
return ProtoBuf.Serializer.Deserialize<T>(new MemoryStream(def.m_Buffer));
else
// Otherwise, return the equivalent of Null.
return default(T);
}
/// <summary>
/// Pack a state type into a State Definition
/// </summary>
/// <typeparam name="T">Gamestate to package up. Upst define protobuf contracts.</typeparam>
/// <param name="state">State to pack up.</param>
/// <returns>A state definition serialized from the passed in state.</returns>
public static StateDefinition Pack<T>(T state) where T:GameState
{
// Using a memory stream, to make sure Garbage Collection knows what's going on.
using (MemoryStream s = new MemoryStream())
{
ProtoBuf.Serializer.Serialize<T>(s, state);
// Uses typeof(T).Name to do semi-enforcement of type safety. Not the best, but it works.
return new StateDefinition(typeof(T).Name, s.ToArray());
}
}
}
}
其他提示
我是Protobuf-net的作者。我还没有添加任何内容来解决直接介绍的情况(除了 Extensible
代码),但我愿意就您的想法建议 应该 做。
我还需要检查“ ProtoC”(我用来解析代码生成之前的Proto Compiler)是否可以区分常规成员和扩展成员。