Question

Je suis peut-être sur quelque chose, mais je tente de battre des tampons de protocole dans une méthode simple pour fournir des extensions plus tard. Cela semble un peu clair, donc je vais sauter directement dans le problème.

Je suis en train d'écrire une assemblée pour soutenir diverses tâches, dont l'une comprend la description des données structurées. moment idéal pour utiliser des tampons de protocole. La classe primaire à utiliser des tampons de protocole est appelé StateDefinition. Voici le fichier .proto je suis venu avec pour elle:

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)

Mon objectif était de permettre à ces messages _StateDef soient étendus plus tard avec ce que les champs dont il aurait besoin. Cependant, cette extension se passerait-il indépendant de la bibliothèque, je suis en train d'écrire.

Kagents.dll ->     Poignées parsing StateDefinition et autres.

Quelque chose Referencing Kagents.dll ->     A un fichier protobuff avec « étendre GraphicsStateDef » pour définir l'état nécessaire.

J'espérais que la définition du « étendre GraphicsStateDef » générerait un code qui me permettrait d'utiliser les propriétés d'accéder à ces champs, et d'éviter la lourdeur « Extendible.AppendValue () » et la syntaxe GetValue ().

Une solution j'ai conçu, qui semble hackish, est de définir une classe dans la DLL de référencement avec des méthodes d'extension, comme suit:

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

Si quelqu'un peut penser à une meilleure façon, je serais bien obligé. =) De plus, je ne sais pas comment ma description lucide du problème est sorti, donc s'il y a des éclaircissements ou de plus amples informations, je peux fournir, s'il vous plaît laissez-moi savoir. =)

EDIT: Ainsi, après avoir beaucoup réfléchi à ce sujet et réalisé que je suis aborder le problème de mal. StateReference est censé stocker une liste des différents GameState de. De plus, il stocke un StateDefinition, qui devrait décrire l'état de cette référence de l'État. À l'heure actuelle, je suis en train de désérialiser les tampons d'état dans différentes classes (GraphicsStateDef), quand je devrais vraiment désérialisation dans l'état des objets eux-mêmes.

Par conséquent, je dois repenser la conception telle que StateDefinition devient un conteneur pour le flux et extrait uniquement les informations suffisantes pour la « répétée StateTypes requiredStates = 1 » champ. Puis, dans l'ensemble de référencement, le reste du cours d'eau peut être désérialisée dans les états respectifs.

Quelqu'un at-il reccomendations pour la façon d'aborder ce sujet? Quelques idées sont la formulation, mais rien de concret, et je serais ravi de l'entrée des autres.

Était-ce utile?

La solution 2

La réponse finale:

D'accord, donc, il y a quelques jours je me suis installé sur une solution et je juste mettre à jour ce au cas où quelqu'un d'autre va dans le même problème.

Tout le problème vient du fait que je ne savais pas protobuf-net pourrait soutenir octet []. Alors, voici ma 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());
            }
        }
    }
}

Autres conseils

Je suis l'auteur de protobuf-net. Je n'ai pas ajouté quoi que ce soit pour traiter le scénario tel que présenté directement (autre que le code Extensible), mais je suis ouvert à la suggestion sur ce que vous pensez devrait faire.

Je aurais besoin aussi de vérifier si « protoc » (le compilateur .proto que j'utilise pour analyser .proto avant la génération de code) me permet de distinguer entre les membres réguliers et prolongés.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top