Pergunta

Talvez estou negligenciando algo, mas estou tentando lutar contra os buffers de protocolo em um método fácil para fornecer extensões mais tarde. Isso parece um pouco claro, então vou pular diretamente para o problema.

Estou escrevendo uma montagem para suportar várias tarefas, uma das quais inclui a descrição de dados estruturados. Tempo perfeito para usar buffers de protocolo. A classe primária para usar os buffers de protocolo é chamada StatedEfinition. Aqui está o arquivo .proto que eu criei para ele:

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)

Meu objetivo era permitir que essas mensagens _statefef fossem estendidas posteriormente com o que os campos precisariam. No entanto, essa extensão aconteceria independentemente da biblioteca que estou escrevendo atualmente.

Kagents.dll -> alças estatais de análise definição e tal.

Algo que referencia Kagents.dll -> tem um arquivo protobuff com "Extend GraphicsStatef" para definir o estado necessário.

Eu esperava que a definição do "Extend GraphicsStateFef" gerasse código que me permitisse usar as propriedades para acessar esses campos e evitar a complicada "extensível.appendValue ()" e a sintaxe getValue ().

Uma solução que eu desenvolvi, que parece hackish, é definir uma classe na DLL de referência com métodos de extensão, assim:

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

Se alguém puder pensar em uma maneira melhor, eu seria muito obrigado. =) Além disso, não tenho certeza de quão lúcida minha descrição do problema foi lançada; portanto, se houver algum esclarecimento ou mais informações que eu possa fornecer, entre em contato. =)

EDIT: Então, depois de pensar muito sobre isso e percebi que estou abordando o problema errado. O StatEreference deve armazenar uma lista de diferentes GameState. Além disso, ele armazena uma definição estatal, que deve descrever o estado dessa referência de estado. Atualmente, estou tentando desserializar os buffers do Estado em diferentes classes (GraphicsStateFef), quando eu realmente deveria estar merecendo os objetos do estado.

Portanto, preciso repensar o design de tal forma que a SayEfinition se torna um contêiner para o fluxo e extrai apenas informações suficientes para o campo "Estatéticos repetidos necessários estatais = 1". Então, na assembléia de referência, o restante do fluxo pode ser desserializado nos respectivos estados.

Alguém tem recomendações sobre como abordar isso? Algumas idéias estão formulando, mas nada concreto, e eu adoraria a contribuição de outras pessoas.

Foi útil?

Solução 2

Resposta final:

Tudo bem, então, alguns dias atrás, eu decidi uma solução e estou apenas atualizando isso, caso qualquer outra pessoa tenha o mesmo problema.

Todo o problema surgiu do fato de que eu não percebi que o Protobuf-Net poderia suportar byte []. Então, aqui está minha solução:

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

Outras dicas

Sou o autor do Protobuf-Net. Não adicionei nada para abordar o cenário como apresentado diretamente (exceto o Extensible código), mas estou aberto a sugestões sobre o que você pensa deve Faz.

Eu também precisaria verificar se o "Protoc" (o compilador .proto que eu uso para analisar .proto antes da geração de código) me permite distinguir entre membros regulares e estendidos.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top