0

基本 Message クラスと、処理可能なメッセージの各タイプを表す Message の約 100 の異なるサブタイプ クラスがあります。私が現在検討しているのは、巨大な switch ステートメントを使用してメッセージ オブジェクトを作成することです。例えば:

switch (MsgType)
{
   case MessageType.ChatMsg:
      Msg = new MsgChat(Buf);
      break;
   case MessageType.ResultMsg:
      Msg = new MsgResult(Buf);
      break;
   ... // 98 more case statements
}
Msg.ProcessMsg(); // Use a polymorphic call to process the message.

これを行うより良い方法はありますか?もしそうなら、簡単なコード例を示していただけますか。

編集

だから、私はこれをやってみました:

public class Test
{
   public Test()
   {
      IEnumerable<Type> myEnumerable = GetTypesWith<MyAttribute>(true);
   }

   IEnumerable<Type> GetTypesWith<TAttribute>(bool inherit)
      where TAttribute : System.Attribute
   {
      return from a in AppDomain.CurrentDomain.GetAssemblies()
             from t in a.GetTypes()
             where t.IsDefined(typeof(TAttribute), inherit)
             select t;
   }
}

これは、myEnumerable に 100 のメッセージ サブタイプすべてと、基本メッセージ タイプも含まれるようになったという点で機能しているように見えます。ただし、プログラムの最初にリフレクションを使用して型を読み込むことは問題ありませんが、リフレクションを使用して適切なオブジェクトにリアルタイムでアクセスするには遅すぎる可能性があります。ということで、デリゲートを使ってみたいと思います。

@Mark Hildreth からの以下のコメントの例:

「それで、> の辞書ができます。次に、マッピングは mappings[MessageType.ChatMsg] = x => new MsgChat(x); になります。」

このコードを解釈するには、いくつかの方法があります。1 つのアイデアは、100 個のサブクラスをすべて削除し、100 個のデリゲート メソッドを含む 1 つの大規模なクラスのみを使用することです。それは遠い第二の選択です。もう 1 つのアイデアと私の最初の選択は、上記のコードでメッセージ サブクラス オブジェクトを作成することです。しかし、私はそれがどのようにこれを行うのかよくわかりません。また、100 個すべてを記述する必要なく、すべての型またはデリゲートを取得する上記の手法を Test クラスに保持するとよいでしょう。あなたまたは他の誰かがこれを行う方法を説明できますか?

4

2 に答える 2

3

switch巨大なステートメントを使用する代わりに、 を定義して、DictionaryMessageType値を定義済みMessageの派生クラスにマップし、このマッピング データを使用してインスタンスを作成できます。

辞書の定義:

Dictionary<int, Type> mappings = new Dictionary<int, Type>();
mappings.Add(MessageType.ChatMsg, typeof(MsgChat));
mappings.Add(MessageType.ResultMsg, typeof(MsgResult));

...

辞書の消費:

ConstructorInfo ctor = mappings[MessageType.ChatMsg].GetConstructor(new[] { typeof(Buf) });
Message message = (Message)ctor.Invoke(new object[] { Buf });

が正しいかどうかを確認するためにこのコードをコンパイルしていないことに注意してください。私はあなたにその考えを示したいだけです。

編集

最初のものを改善するための私の新しい答えがあります。@MikeSW@Mark Hildrethから与えられたアイデアを使用して、編集した質問について考えています。

public class FactoryMethodDelegateAttribute : Attribute
{
    public FactoryMethodDelegateAttribute(Type type, string factoryMethodField, Message.MessageType typeId)
    {
        this.TypeId = typeId;
        var field = type.GetField(factoryMethodField);
        if (field != null)
        {
            this.FactoryMethod = (Func<byte[], Message>)field.GetValue(null);
        }
    }

    public Func<byte[], Message> FactoryMethod { get; private set; }
    public Message.MessageType TypeId { get; private set; }
}

public class Message
{
    public enum MessageType
    {
        ChatMsg,
    }
}

[FactoryMethodDelegate(typeof(ChatMsg), "FactoryMethodDelegate", Message.MessageType.ChatMsg)]
public class ChatMsg : Message
{
    public static readonly MessageType MessageTypeId = MessageType.ChatMsg;
    public static readonly Func<byte[], Message> FactoryMethodDelegate = buffer => new ChatMsg(buffer);
    public ChatMsg(byte[] buffer)
    {
        this.Buffer = buffer;
    }

    private byte[] Buffer { get; set; }
 }

public class TestClass
{
    private IEnumerable<Type> GetTypesWith<TAttribute>(bool inherit) where TAttribute : Attribute
    {
        return from a in AppDomain.CurrentDomain.GetAssemblies()
               from t in a.GetTypes()
               where t.IsDefined(typeof(TAttribute), inherit)
               select t;
    }

    [Test]
    public void Test()
    {
        var buffer = new byte[1];
        var mappings = new Dictionary<Message.MessageType, Func<byte[], Message>>();
        IEnumerable<Type> types = this.GetTypesWith<FactoryMethodDelegateAttribute>(true);
        foreach (var type in types)
        {
            var attribute =
                (FactoryMethodDelegateAttribute)
                type.GetCustomAttributes(typeof(FactoryMethodDelegateAttribute), true).First();

            mappings.Add(attribute.TypeId, attribute.FactoryMethod);
        }

        var message = mappings[Message.MessageType.ChatMsg](buffer);
    }
}
于 2013-02-05T22:13:42.170 に答える
2

あなたは正しい方向に進んでおり、辞書を使用することは良い考えです。リフレクションが遅すぎる場合は、次のような式を使用できます(MessagesクラスをMessageTypeAttributeで装飾すると想定しています)。

public class Test
{
 public Test()
  {
     var dict=new Dictionary<MessageType,Func<Buffer,Mesage>>();
     var types=from a in AppDomain.CurrentDomain.GetAssemblies()
         from t in a.GetTypes()
         where t.IsDefined(MessageTypeAttribute, inherit)
         select t;
    foreach(var t in types) {
      var attr = t.GetCustomAttributes(typeof (MessageTypeAttribute), false).First();
       dict[attr.MessageType] = CreateFactory(t);
       }

      var msg=dict[MessageType.Chat](Buf);
  }

 Func<Buffer,Message> CreateFactory(Type t)
 {
      var arg = Expression.Parameter(typeof (Buffer));
        var newMsg = Expression.New(t.GetConstructor(new[] {typeof (Buffer)}),arg);
        return Expression.Lambda<Func<Buffer, Message>>(newMsg, arg).Compile();
}

}
于 2013-02-06T11:20:14.227 に答える