Frage

Ich habe vielleicht etwas übersehen, aber ich versuche, Protokollpuffer in eine einfache Methode zur späteren Bereitstellung von Verlängerungen zu ringen. Das scheint ein bisschen unklar zu sein, also werde ich direkt in das Problem einsteigen.

Ich schreibe eine Baugruppe, um verschiedene Aufgaben zu unterstützen, von denen eines die Beschreibung strukturierter Daten umfasst. Perfekte Zeit, um Protokollpuffer zu verwenden. Die primäre Klasse für die Verwendung von Protokollpuffern wird als erklärte Definition bezeichnet. Hier ist die .Proto -Datei, die ich mir für sie ausgedacht habe:

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)

Mein Ziel war es, diesen _statedef -Nachrichten später mit den Feldern zu erweitern, die sie benötigen würden. Diese Erweiterung würde jedoch unabhängig von der Bibliothek geschehen, die ich gerade schreibe.

Kagents.dll -> Handles behauptete Definition Parsing und dergleichen.

Etwas, das auf Kagents bezieht.

Ich hatte gehofft, dass das Definieren des "Extend GraphicsStatedEF" Code generieren würde, mit dem ich Eigenschaften zum Zugriff auf diese Felder verwenden und die umständliche "extendible.AppendValue ()" und GetValue () -Syntax vermeiden kann.

Eine Lösung, die ich entwickelt habe, die hackisch erscheint, besteht darin, eine Klasse in der Referenzierungsdll mit Erweiterungsmethoden wie SO zu definieren:

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

Wenn sich jemand einen besseren Weg vorstellen kann, wäre ich sehr verpflichtet. =) Ich bin mir auch nicht sicher, wie klar meine Beschreibung des Problems herauskam. =))

Bearbeiten: Nachdem ich viel darüber nachgedacht und festgestellt hatte, dass ich mich dem Problem falsch nähere. Statereference soll eine Liste verschiedener GameState speichern. Außerdem speichert es eine erklärte Definition, die den Zustand dieses Zustands beschreiben sollte. Derzeit versuche ich, die staatlichen Puffer in verschiedene Klassen (GraphicsStatedEF) zu deserialisieren, wenn ich wirklich in die Zustandsobjekte selbst deserialisieren sollte.

Daher muss ich das Design so überdenken, dass die angegebene Definition zum Container für den Stream wird und nur genügend Informationen für das Feld "Wiederholte Statetypen benötigt" extrahiert. In der Referenzversammlung kann der Rest des Stroms in die jeweiligen Zustände deserialisiert werden.

Hat jemand Empfehlungen dafür, wie er sich daran nähert? Ein paar Ideen sind formuliert, aber nichts Konkretes, und ich würde den Einfluss anderer lieben.

War es hilfreich?

Lösung 2

Endgültige Antwort:

Okay, vor ein paar Tagen habe ich mich für eine Lösung entschieden und aktualisiere dies nur, falls jemand anderes auf das gleiche Problem geht.

Das ganze Problem beruhte auf der Tatsache, dass ich nicht bemerkte, dass Protobuf-Net Byte [] unterstützen konnte. Also, hier ist meine Lösung:

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

Andere Tipps

Ich bin der Autor von Protobuf-Net. Ich habe nichts hinzugefügt, um das direkt dargestellte Szenario anzugehen (außer dem Extensible Code), aber ich bin offen für Vorschläge, was Sie denken, es sollte tun.

Ich müsste auch prüfen, ob "Protoc" (der .Proto -Compiler, mit dem ich vor der Codegenerierung .Proto analysiert werde) es mir ermöglicht, zwischen regulären und erweiterten Mitgliedern zu unterscheiden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top