12

パケットの関連付けが列挙型によって行われるサーバーライブラリを作成しています。

public enum ServerOperationCode : byte
{
    LoginResponse = 0x00,
    SelectionResponse = 0x01,
    BlahBlahResponse = 0x02
}

public enum ClientOperationCode : byte
{
    LoginRequest = 0x00,
    SelectionRequest = 0x01,
    BlahBlahRequest = 0x02
}

自分のプロジェクトで作業している場合は問題なく機能します。返される列挙型メンバーを比較できます(つまりif (packet.OperationCode == ClientOperationCode.LoginRequest))。ただし、これはクラスライブラリであるため、ユーザーは独自の列挙型を定義する必要があります。

したがって、「abstract」として追加する2つの列挙型(ServerOperationCodeとClientOperationCode)があります。C#で抽象列挙型を実装することは不可能です。どうすればこれを行うことができますか?

4

7 に答える 7

14

これを行う必要がある場合、クラスで静的インスタンスを使用するのが好きです。いくつかのデフォルト値を持つことができますが、継承とインターフェースの実装という通常の方法で拡張することもできます:

    public abstract class OperationCode
    {
        public byte Code { get; private set; }
        public OperationCode(byte code)
        {
            Code = code;
        }
    }

    public class ServerOperationCode : OperationCode
    {
        public static ServerOperationCode LoginResponse = new ServerOperationCode(0x00);
        public static ServerOperationCode SelectionResponse = new ServerOperationCode(0x01);
        public static ServerOperationCode BlahBlahResponse = new ServerOperationCode(0x02);

        public ServerOperationCode(byte code) : base(code) { }
    }

    public class ClientOperationCode : OperationCode
    {
        public static ClientOperationCode LoginRequest = new ClientOperationCode(0x00);
        public static ClientOperationCode SelectionRequest = new ClientOperationCode(0x01);
        public static ClientOperationCode BlahBlahRequest = new ClientOperationCode(0x02);

        public ClientOperationCode(byte code) : base(code) { }
    }

バイトを返すと仮定packet.OperationCodeすると、おそらくバイトに対して == 演算子を実装する必要があります。このコードを抽象的な OperationCode クラスに入れます。

public static bool operator ==(OperationCode a, OperationCode b)
{
  return a.Code == b.Code;
}

public static bool operator !=(OperationCode a, OperationCode b)
{
  return !(a == b);
}

これにより、示したのと同じチェックを行うことができます。

if (packet.OperationCode == ClientOperationCode.LoginRequest)
于 2010-06-13T03:23:13.253 に答える
0

しばらく前に同様のシナリオでメッセージ切り替えライブラリを作成し、ジェネリックを使用してユーザー定義の列挙型を渡すことにしました。これに関する主な問題は、ジェネリックを列挙型のみに制限することはできず、while T: struct としか言えないことです。誰かがあなたの型を他のプリミティブ型でインスタンス化するかもしれません (ただし、すべてが一意の値であれば、int を使用しても機能する可能性があります。そうでない場合、辞書は例外をスローします。リフレクションを使用して追加のチェックを追加することもできます。列挙型を渡すようにしてください。

public abstract class DefaultMessageHandler<T> : IMessageHandler<T> where T : struct {
    public delegate void MessageHandlerDelegate(IMessage<T> message, IConnection connnection);

    private readonly IDictionary<T, MessageHandlerDelegate> messageHandlerDictionary = 
        new Dictionary<T, MessageHandlerDelegate>();

    protected void RegisterMessageHandler(T messageType, MessageHandlerDelegate handler) {
        if (this.messageHandlerDictionary.ContainsKey(messageType)) 
            return;
        else this.messageHandlerDictionary.Add(messageType, handler);
    }

    protected void UnregisterMessageHandler(T messageType) {
        if (this.messageHandlerDictionary.ContainsKey(messageType))
            this.messageHandlerDictionary.Remove(messageType);
    }

    protected virtual void HandleUnregisteredMessage(IMessage<T> message, IConnection connection) {
    }

    void IMessageHandler<T>.HandleMessage(IMessage<T> message, IConnection connection) {
        if (this.messageHandlerDictionary.ContainsKey(message.MessageType))
            this.messageHandlerDictionary[message.MessageType].Invoke(message, connection);
        else HandleUnregisteredMessage(message, connection);
    }
}

例のシナリオを考えると、このようにサブクラス化するだけです。

public sealed class ServerOperationHandler : DefaultMessageHandler<ServerOperationCode> {
    public ServerOperationHandler() {
        this.RegisterMessageHandler(ServerOperationCode.LoginResponse, this.HandleLoginResponse);
        this.RegisterMessageHandler(ServerOperationCode.SelectionResponse, this.HandleSelectionResponse);
    }

    private void HandleLoginResponse(IMessage<ServerOperationCode> message, IConnection connection) {
        //TODO
    }

    private void HandleSelectionResponse(IMessage<ServerOperationCode> message, IConnection connection) {
        //TODO
    }
}
于 2010-06-13T10:21:12.273 に答える
0

静的 Dictionary と仮想メソッドを使用して、継承されたクラスの静的辞書を取得するのはどうですか?

あなたの場合は次のように:

    public abstract class Operation
    {
        protected abstract Dictionary<string, int> getCodeTable();
        public int returnOpCode(string request){ return getCodeTable()[request]; }
    }
    public class ServerOperation : Operation
    {
        Dictionary<string, int> serverOpCodeTable = new Dictionary<string, int>()
        {
            {"LoginResponse", 0x00,},
            {"SelectionResponse", 0x01},
            {"BlahBlahResponse", 0x02}
        };
        protected override Dictionary<string, int> getCodeTable()
        {
            return serverOpCodeTable;
        }

    }
    public class ClientOperation : Operation
    {
        Dictionary<string, int> cilentOpCodeTable = new Dictionary<string, int>()
        {
            {"LoginResponse", 0x00,},
            {"SelectionResponse", 0x01},
            {"BlahBlahResponse", 0x02}
        };
        protected override Dictionary<string, int> getCodeTable()
        {
            return cilentOpCodeTable;
        }
    }
于 2014-01-21T06:13:09.227 に答える
0

ライブラリのクライアントによって拡張できる列挙型が必要だと言いたい場合は、トピックに関する CodeProject の記事、拡張可能な列挙型としてのシンボル を確認してください。

私のライブラリでは、ネットワーク上で値を交換するためではなく、単一のプログラム内で使用するように設計されているため、Symbol は「列挙値」の ID 番号を自動的に選択することに注意してください。ただし、クライアントが定数値をシンボルに割り当てられるように、Symbol.cs を好みに合わせて変更することは可能かもしれません。

于 2010-06-13T03:03:31.893 に答える
0
  1. LoginResponse、SelectionResponse などの Enum を作成しますが、値は指定しません。

  2. ServerOperationCode と ClientOperationCode に、整数バイトコードを指定すると Enum から適切な値を返す関数を実装させます。

例:

public enum OperationCode
{
 LoginResponse,
 SelectionResponse,
 BlahBlahResponse
}

public interface IOperationCodeTranslator {
 public OperationCode GetOperationCode(byte inputcode);
 }

public class ServerOperationCode : IOperationCodeTranslator
{
  public OperationCode GetOperationCode(byte inputcode) {
    switch(inputcode) {
       case 0x00: return OperationCode.LoginResponse;
      [...]
    } 
}

警告: インターフェイスは静的関数を定義できないため、関数がインスタンス関数である場合、ServerOperationCode と ClientOperationCode は共通インターフェイスのみを実装できます。共通のインターフェイスを実装する必要がない場合は、GetOperationCode を静的関数にすることができます。

(C# のスナフスについてはお詫びします。これは私の母国語ではありません...)

于 2010-06-13T03:10:26.103 に答える
0

クライアント アプリケーションとサーバー アプリケーションの間で共有されるデータベースがある場合は、ルックアップ テーブルが役立つことがあります。テーブル構造には、整数値 (ID) と文字列 (名前) だけが含まれます。このテーブルは、アプリケーションのいずれかの側 (クライアントまたはサーバー) で入力され、他方で読み取られます。これらのテーブルを(コード内で)辞書にキャッシュして、すばやく検索できます。

app.config ファイルに同じことを実装することもできます。ライブラリのユーザーに、ライブラリが簡単にアクセスできる app.config ファイルでこれらの値を設定するように強制します。

于 2010-06-13T03:20:17.440 に答える