协议缓冲器,具有扩展 [英] Protocol Buffers with Extensions

查看:170
本文介绍了协议缓冲器,具有扩展的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我也许忽视的东西,但我试图搏斗协议缓冲区变成一个简单的方法供以后提供的扩展。这似乎有点不清楚,所以我会直接跳入问题。



我写一个程序集,以支持各种任务,其中之一包括描述的结构化数据。完美时空使用协议缓冲区。使用协议缓冲区主类被称为StateDefinition。这是我想出了它的.proto文件:

 
包Kannon.State;
消息StateDefinition {
枚举StateTypes {
GRAPHICS = 0;
AUDIO = 1;
MIND = 2;
物理= 3;
网络= 4;
GENERIC = 5;
}
重复StateTypes requiredStates = 1;
可选GraphicsStateDef显卡= 2;
可选AudioStateDef音频= 3;
(ETC)
}

消息GraphicsStateDef {
分机100 MAX;
}

消息AudioStateDef {
分机100 MAX;
}
(ETC)



我的目标是让那些_StateDef消息后来与场什么扩展那就需要。然而,这个扩展会发生独立我目前正在写的库



Kagents.dll - >
把手StateDefinition解析和这样



东西引用Kagents.dll - >
已经与延长GraphicsStateDef来定义所需的状态protobuff文件



<。 p>我希望界定延长GraphicsStateDef将生成代码,将允许我使用属性来访问这些字段,避免了烦琐的Extendible.AppendValue()和getValue()语法。



一个解决方案,我提出的,这似乎hackish的,是引用的DLL来定义一个类扩展方法,像这样:

 
公共静态类GraphicsExt
{
枚举字段
{
someValue中= 1,
someOtherValue = 2
}

公共静态的Int32 someValue中(此State.GraphicsStateDef DEF)
{
返回Extensible.GetValue(DEF,Fields.someValue);
}
公共静态无效someValue中(这State.graphicsStateDef闪避,的Int32值)
{
Extensible.AppendValue(DEF,fields.someValue,价值);
}
}

如果任何人都可以想出一个更好的办法,我将非常感激。 =)
还有,我不知道我的问题描述如何明晰出来,所以如果有任何澄清或进一步的信息,我可以提供,请让我知道。 =)



编辑:
所以,思考了很多关于这之后,意识到我快到的问题是错误的。
StateReference是应该存储不同游戏状态的列表。同时,它存储StateDefinition,这应该描述这种状态基准的状态。目前,我尝试反序列化态缓冲器到不同的类别(GraphicsStateDef),当我真的应该反序列化进入状态对象本身。



所以,我需要重新考虑设计使得StateDefinition成为容器的流并提取用于重复StateTypes requiredStates = 1字段只有足够的信息。然后,在引用组装,流的其他部分可以反序列化到各自的状态。



有没有人有如何处理这个建议步骤? 。一些想法正在制定,但没有具体的,我喜欢别人的输入


解决方案

最后的答案:



好了,所以,前几天我最后选择了一个解决方案,我只是这个更新的情况下,任何人都跑进了同样的问题。



整个问题的事实,我没有意识到protobuf网可以支持的byte []朵朵。所以,这里是我的解决方案:

 命名空间Kannon.State 
{
///<总结>
/// ReferenceDefinition描述的一般参考的布局。
///它会告诉什么规定它应该有,并存储供以后序列化流缓冲区。
///< /总结>
[ProtoBuf.ProtoContract]
公共类ReferenceDefinition
{
///<总结>
///有几个在建状态的类型,以及为一般状态的基本支持。
///< /总结>
公共枚举StateType
{
图形= 0,$ B $ 2音频,
心灵,
物理,
网,
通用
}

///<总结>
///代表状态应该是什么存在于ReferenceDefinition
///< /总结>
[ProtoBuf.ProtoMember(1)]
名单,LT; StateType> m_StatesPresent =新的List< StateType>();

///<总结>
///代表StateDefinitions,它保持每个不同类型的状态的缓冲器列表。
///< /总结>
[ProtoBuf.ProtoMember(2)]
名单,LT; StateDefinition> m_StateDefinition =新的List< StateDefinition>();

///<总结>
///添加一个状态,映射到一个类型,这个参考定义。
///< /总结>
///< PARAM NAME =输入>类型的国家加入< /参数>
///< PARAM NAME =高清>状态定义添加< /参数>
公共无效AddState(StateType类型,StateDefinition DEF)
{
//强制只每种型号1,除通用,它可以有它想要尽可能多。
如果(m_StatesPresent.Contains(类型)及和放大器;!键入= StateType.Generic)
的回报;
m_StatesPresent.Add(类型);
m_StateDefinition.Add(DEF);
}
}

///<总结>
///表示一些游戏状态的定义,存储protobuffered数据重新映射到的状态。
///< /总结>
[ProtoBuf.ProtoContract]
公共类StateDefinition
{
///<总结>
///状态
///<的名称; /总结>
[ProtoBuf.ProtoMember(1)]
串m_StateName;
///<总结>
///字节数组来存储数据为以后系列化。
///< /总结>
[ProtoBuf.ProtoMember(2)]
字节[] m_Buffer;

///<总结>
///构造函数状态定义,保护,执行包和解压功能,以保平安。
///< /总结>
///< PARAM NAME =名方式>状态类型的名称和LT; /参数>
///< PARAM NAME =BUFF>字节的缓冲区建立国家断< /参数>
保护StateDefinition(字符串名称,字节[] BUFF)
{
m_StateName =名称;
m_Buffer = BUFF;
}

///<总结>
///从包装中取出StateDefinition进入游戏状态
///< /总结>
///< typeparam NAME =T>游戏状态类型解压到。必须定义的Protobuf合同< / typeparam>
///< PARAM NAME =高清>状态定义解压< /参数>
///<返回>在解压的状态数据< /回报>
公共静态牛逼拆包< T>(StateDefinition DEF),其中T:游戏状态
{
//确保我们拆包到正确的状态类型。
如果(typeof运算(T).Name点== def.m_StateName)
返回ProtoBuf.Serializer.Deserialize< T>(新的MemoryStream(def.m_Buffer));
,否则
//否则,返回null的等价物。
返回默认值(T);
}

///<总结>
///包的状态类型到状态定义
///< /总结>
///< typeparam NAME =T>游戏状态来打包。 Upst定义protobuf的合同< / typeparam>
///< PARAM NAME =状态>状态收拾< /参数>
///<返回>从状态传递的序列化状态定义< /回报>
公共静态StateDefinition包装< T>(T状态)T:游戏状态
{
//使用内存流,以确保垃圾收集知道发生了什么事。使用
(MemoryStream的S =新的MemoryStream())
{
ProtoBuf.Serializer.Serialize< T>(S,状态);
//使用的typeof(T).Name点做类型安全的半强制执行。不是最好的,但它的作品。
返回新StateDefinition(typeof运算(T).name和s.ToArray());
}
}
}
}


I'm perhaps overlooking something, but I'm attempting to wrestle protocol buffers into an easy method for providing extensions later. That seems a bit unclear so I'll jump directly into the problem.

I am writing an assembly to support various tasks, one of which includes describing structured data. Perfect time to use protocol buffers. The primary class to use protocol buffers is called StateDefinition. Here's the .proto file I came up with for it:

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)

My goal was to allow those _StateDef messages to be extended later with what the fields it would need. However, this extension would happen independent of the library I'm currently writing.

Kagents.dll -> Handles StateDefinition parsing and such.

Something Referencing Kagents.dll -> Has a protobuff file with "extend GraphicsStateDef" to define the state needed.

I was hoping that defining the "extend GraphicsStateDef" would generate code that would allow me to use properties to access these fields, and avoid the cumbersome "Extendible.AppendValue()" and GetValue() syntax.

One solution I devised, which seems hackish, is to define a class in the referencing DLL with extension methods, like so:

    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);
        }
    }

If anyone can think of a better way, I would be much obliged. =) Also, I'm not sure how lucid my description of the problem came out, so if there's any clarification or further information I can provide, please let me know. =)

EDIT: So, After thinking a lot about this and realized I'm approaching the problem wrong. StateReference is supposed to store a list of different GameState's. As well, it stores a StateDefinition, which should describe the state of this state reference. Currently, I'm trying to deserialize the state buffers into different classes (GraphicsStateDef), when I really should be deserializing into the state objects themselves.

Therefore, I need to rethink the design such that StateDefinition becomes a container for the stream and extracts only enough information for the "repeated StateTypes requiredStates=1" field. Then, in the referencing assembly, the rest of the stream can be deserialized into the respective states.

Does anyone have reccomendations for how to approach this? A few ideas are formulating, but nothing concrete, and I'd love the input of others.

解决方案

Final answer:

Alright, so, A few days ago I settled on a solution and I'm just updating this in case anyone else runs into the same issue.

The whole problem stemmed from the fact that I didn't realize protobuf-net could support byte[]. So, here's my solution:

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());
            }
        }
    }
}

这篇关于协议缓冲器,具有扩展的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆