3

私はおそらく何かを見落としていますが、後で拡張機能を提供するための簡単な方法にプロトコルバッファを取り組もうとしています。それは少し不明確に思えるので、私は直接問題に飛び込みます。

構造化データの記述を含むさまざまなタスクをサポートするアセンブリを作成しています。プロトコルバッファを使用する絶好のタイミング。プロトコルバッファを使用するプライマリクラスは、StateDefinitionと呼ばれます。これが私が思いついた.protoファイルです:

パッケージKannon.State;
メッセージStateDefinition{
    列挙型StateTypes{
        グラフィック=0;
        オーディオ=1;
        MIND = 2;
        物理学=3;
        ネットワーク=4;
        GENERIC = 5;
    }
    繰り返されるStateTypesrequiredStates= 1;
    オプションのGraphicsStateDefGraphics= 2;
    オプションのAudioStateDefAudio= 3;
         (等)
}

メッセージGraphicsStateDef{
    最大100までの拡張。
}

メッセージAudioStateDef{
    最大100までの拡張。
}
    (等)

私の目標は、これらの_StateDefメッセージを、必要なフィールドで後で拡張できるようにすることでした。ただし、この拡張機能は、現在作成しているライブラリとは関係なく発生します。

Kagents.dll->StateDefinitionの解析などを処理します。

Kagents.dllを参照するもの->必要な状態を定義するための「extendGraphicsStateDef」を含むprotobuffファイルがあります。

「extendGraphicsStateDef」を定義すると、プロパティを使用してこれらのフィールドにアクセスし、面倒な「Extendible.AppendValue()」およびGetValue()構文を回避できるコードが生成されることを期待していました。

私が考案した解決策の1つは、ハックのようですが、次のような拡張メソッドを使用して、参照DLLでクラスを定義することです。

    public static class GraphicsExt
    {{
        列挙型フィールド
        {{
            someValue = 1、
            someOtherValue = 2
        }

        public static Int32 someValue(this State.GraphicsStateDef def)
        {{
            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」フィールドに十分な情報のみを抽出するように、設計を再考する必要があります。次に、参照アセンブリで、ストリームの残りの部分をそれぞれの状態に逆シリアル化できます。

これにアプローチする方法について誰かが推奨事項を持っていますか?いくつかのアイデアが策定されていますが、具体的なものは何もありません。他の人の意見を取り入れたいと思います。

4

2 に答える 2

0

最終的な答え:

よし、そう、数日前に私は解決策に落ち着きました。他の誰かが同じ問題に遭遇した場合に備えて、これを更新しています。

全体の問題は、protobuf-net が byte[] をサポートできることに気付いていなかったという事実から生じました。だから、ここに私の解決策があります:

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());
            }
        }
    }
}
于 2009-08-20T17:33:29.010 に答える