具有扩展的协议缓冲区
我可能忽略了一些东西,但我正在尝试将协议缓冲区转换为一种简单的方法,以便稍后提供扩展。 这似乎有点不清楚,所以我会直接跳到这个问题。
我正在编写一个程序集来支持各种任务,其中一个任务包括描述结构化数据。 使用协议缓冲区的最佳时机。 使用协议缓冲区的主类称为StateDefinition。 这是我为它提出的.proto文件:
包Kannon.State; 消息StateDefinition { 枚举StateTypes { GRAPHICS = 0; AUDIO = 1; MIND = 2; 物理= 3; NETWORK = 4; GENERIC = 5; } 重复StateTypes requiredStates = 1; 可选GraphicsStateDef Graphics = 2; 可选AudioStateDef Audio = 3; (等等) } 消息GraphicsStateDef { 扩展100到最大; } 消息AudioStateDef { 扩展100到最大; } (等等)
我的目标是允许稍后使用所需的字段扩展那些_StateDef消息。 但是,此扩展将独立于我正在编写的库。
Kagents.dll – >处理StateDefinition解析等。
引用Kagents.dll的东西 – >有一个带有“extend GraphicsStateDef”的protobuff文件来定义所需的状态。
我希望定义“extend GraphicsStateDef”会生成允许我使用属性来访问这些字段的代码,并避免使用繁琐的“Extendible.AppendValue()”和GetValue()语法。
我设计的一个似乎是hackish的解决方案是使用扩展方法在引用DLL中定义一个类,如下所示:
public static class GraphicsExt { 枚举字段 { 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应该存储不同GameState的列表。 同样,它存储StateDefinition,它应描述此状态引用的状态。 目前,我正在尝试将状态缓冲区反序列化为不同的类(GraphicsStateDef),而我真的应该反序列化为状态对象本身。
因此,我需要重新考虑设计,使StateDefinition成为流的容器,并为“重复的StateTypes requiredStates = 1”字段提取足够的信息。 然后,在引用程序集中,可以将流的其余部分反序列化为相应的状态。
有没有人有关于如何处理此问题的建议? 一些想法正在制定,但没有具体的,我喜欢别人的意见。
我是protobuf-net的作者。 我没有添加任何东西来解决直接呈现的场景(除了Extensible
代码),但我愿意接受你认为它应该做什么的建议。
我还需要检查“protoc”(我在代码生成之前用来解析.proto的.proto编译器)是否允许我区分常规成员和扩展成员。
最终答案:
好吧,所以,几天前我找到了一个解决方案,我只是更新这个,以防其他人遇到同样的问题。
整个问题源于我没有意识到protobuf-net可以支持byte []。 所以,这是我的解决方案:
namespace Kannon.State { /// /// ReferenceDefinition describes the layout of the reference in general. /// It tells what states it should have, and stores the stream buffers for later serialization. /// [ProtoBuf.ProtoContract] public class ReferenceDefinition { /// /// There are several built in state types, as well as rudimentary support for a "Generic" state. /// public enum StateType { Graphics=0, Audio, Mind, Physics, Network, Generic } /// /// Represents what states should be present in the ReferenceDefinition /// [ProtoBuf.ProtoMember(1)] List m_StatesPresent = new List (); /// /// Represent a list of StateDefinitions, which hold the buffers for each different type of state. /// [ProtoBuf.ProtoMember(2)] List m_StateDefinition = new List (); /// /// Add a state, mapped to a type, to this reference definition. /// /// Type of state to add /// State definition to add. 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); } } /// /// Represents a definition of some gamestate, storing protobuffered data to be remapped to the state. /// [ProtoBuf.ProtoContract] public class StateDefinition { /// /// Name of the state /// [ProtoBuf.ProtoMember(1)] string m_StateName; /// /// Byte array to store the "data" for later serialization. /// [ProtoBuf.ProtoMember(2)] byte[] m_Buffer; /// /// Constructor for the state definition, protected to enforce the Pack and Unpack functionality to keep things safe. /// /// Name of the state type. /// byte buffer to build state off of protected StateDefinition(String name, byte[] buff) { m_StateName = name; m_Buffer = buff; } /// /// Unpack a StateDefinition into a GameState /// /// Gamestate type to unpack into. Must define Protobuf Contracts. /// State Definition to unpack. /// The unpacked state data. public static T Unpack(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 (new MemoryStream(def.m_Buffer)); else // Otherwise, return the equivalent of Null. return default(T); } /// /// Pack a state type into a State Definition /// /// Gamestate to package up. Upst define protobuf contracts. /// State to pack up. /// A state definition serialized from the passed in state. public static StateDefinition Pack (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 (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()); } } } }