none
有關訊息佇列的概念 RRS feed

  • 問題

  • 小弟想做個簡單的模擬,
    環境為:1個處理訊息的分析器,多個發送訊息端,假設為server及多個client。
    client會不斷傳送訊息至server,server必須parse後做對應的處理。
    client發送的訊息可能相當多種,且資料長度各自不同
    舉例來說:

    訊息種類有以下三種,每種訊息的內容及長度皆不同
        class Alarm    
        {
            public int clientID;          
            public int AlarmType;
    
        }
    
        class ReportLocation
        {
            public int clientID;
            public string address;
        }
    
        class RequestService
        {
            public int clientID;
            public int serviceType;
            public string address;
        }
    小弟希望用一個自己定義的Message Queue來存放這些訊息,並能夠按順序取出並做相對應的處理
    此時遇到的問題便是,須要一個能放入不同型別資料的容器,且取出後能夠分辨不同的型別來做對應的處理

    小弟自己想到的做法是,外包一層class,並將訊息內容存為object,類似下列作法

        class Message
        {
            public int type;
            object message = new object();
        }
    並用下列方式放入資料

        public List<Message> myMessage = new List<Message>(); 
        Message msg = new Message();
        myMessage.Add(msg);
    取出時便依type類將object做強制轉型來取出資料


    另外一種想法是 ,將所有須要的屬性放在一起,然後要用的的部份給值,其它設為null...

        class Message
        {
            public int type;
            public int clientID;
            public int AlarmType;
            public string address;
            public int serviceType;
        }
    但想想都不是好做法,這個做法其實相當類似網路中的封包分析,依照header來分辨內容資料,但在packet分析時,C語言可以使用指標及struct來達到此效果

    想請教大家,使用C#時,是否有較好的方法來達成此目標

    2010年3月8日 上午 04:28

解答

  • Hi,

    經你回覆
    我感覺還是這樣寫沒錯
    參考一下
        class Program
        {
            static void Main(string[] args)
            {
                List<Message> msgList = new List<Message> { new Alarm(),new ReportLocation(),new RequestService() };
                foreach (Message msg in msgList)
                {
                    string msgType = "";
                    if (msg is Alarm)
                        msgType = "Alarm";
                    else if (msg is ReportLocation)
                        msgType = "ReportLocation";
                    else
                        msgType = "RequestService";
    
                    Console.WriteLine ("MsgType : " + msg.GetType().ToString());
                    Console.WriteLine("ClientID : " + msg.clientID.ToString());
                    Console.WriteLine ("");
                }
            }
        }
    
        abstract class Message
        {
            public int clientID;
        }
    
        class Alarm : Message
        {
            public int AlarmType;
    
        }
    
        class ReportLocation : Message
        {
            public string address;
        }
    
        class RequestService : Message
        {
            public int serviceType;
            public string address;
        }


    謙卑學習,持之以恆,才能不斷的Level Up http://www.dotblogs.com.tw/larrynung/
    • 已標示為解答 宙斯 2010年3月8日 上午 07:11
    2010年3月8日 上午 05:47
  • interface IMessage{
    }

      public   class Alarm : IMessage
        {
        }

      public   class ReportLocation : IMessage
        {
        }

      public   class RequestService : IMessage
        {
        }

    public static class MessageHandle{
             public static  void ProcessMessage(Alarm message){
                  if(message !=null){
                    ..........
                  }
             }
            public static  void ProcessMessage(ReportLocation message){
                  if(message !=null){
                    ..........
                  }
             }
           public static void ProcessMessage(RequestService message){
                  if(message !=null){
                    ..........
                  }
             }
    }

     class Program
        {
            static void Main(string[] args)
            {
                List<Message> msgList = new List<Message> { new Alarm(),new ReportLocation(),new RequestService() };
                foreach (Message msg in msgList)
                {
                    string msgType = "";
                    if (msg is Alarm)
                        MessageHandle.ProcessMessage((Alarm)msg);
                    else if (msg is ReportLocation)
                         MessageHandle.ProcessMessage((ReportLocation)msg);
                    else
                     MessageHandle.ProcessMessage((RequestService )msg);
                }
            }
        }

    • 已標示為解答 宙斯 2010年3月8日 上午 07:11
    2010年3月8日 上午 06:26

所有回覆

  • Hi.

    為何不建立一個訊息的抽象類別
    把三種訊息共同的成員放到該抽象類別
    三種訊息繼承自該抽象類別?

        abstract class Message
        {
            public int clientID;          
        }

        class Alarm : Message
        {   
            public int AlarmType;
    
        }
    
        class ReportLocation: Message
        {
            public string address;
        }
    
        class RequestService: Message
        {
            public int serviceType;
            public string address;
        }

    謙卑學習,持之以恆,才能不斷的Level Up http://www.dotblogs.com.tw/larrynung/
    2010年3月8日 上午 04:44
  • 感謝您的建議,使用抽象類別的確可以將共用部份抽出,就像packet時的header般,而繼承部份則為各自相異部份的訊息

    但使用上,Alarm、 ReportLocation、RequestService仍是三個獨立的class,new完後,仍是三個欄位個數、大小皆不同的instance,不知道是否有什麼通用型別的容器,來放置這些相異型別(class)的變數,並使用如

    public List<Message> myMessage = new List<Message>(); 
    來放入,並在取出時能夠判斷型別來獲的對應的欄位值

    也就是說,將不同種類的訊息放入同一個queue中,並能夠在取出時正確判斷、並取出對應欄位的值

    還請不吝指教
    2010年3月8日 上午 05:24
  • Hi,

    經你回覆
    我感覺還是這樣寫沒錯
    參考一下
        class Program
        {
            static void Main(string[] args)
            {
                List<Message> msgList = new List<Message> { new Alarm(),new ReportLocation(),new RequestService() };
                foreach (Message msg in msgList)
                {
                    string msgType = "";
                    if (msg is Alarm)
                        msgType = "Alarm";
                    else if (msg is ReportLocation)
                        msgType = "ReportLocation";
                    else
                        msgType = "RequestService";
    
                    Console.WriteLine ("MsgType : " + msg.GetType().ToString());
                    Console.WriteLine("ClientID : " + msg.clientID.ToString());
                    Console.WriteLine ("");
                }
            }
        }
    
        abstract class Message
        {
            public int clientID;
        }
    
        class Alarm : Message
        {
            public int AlarmType;
    
        }
    
        class ReportLocation : Message
        {
            public string address;
        }
    
        class RequestService : Message
        {
            public int serviceType;
            public string address;
        }


    謙卑學習,持之以恆,才能不斷的Level Up http://www.dotblogs.com.tw/larrynung/
    • 已標示為解答 宙斯 2010年3月8日 上午 07:11
    2010年3月8日 上午 05:47
  • interface IMessage{
    }

      public   class Alarm : IMessage
        {
        }

      public   class ReportLocation : IMessage
        {
        }

      public   class RequestService : IMessage
        {
        }

    public static class MessageHandle{
             public static  void ProcessMessage(Alarm message){
                  if(message !=null){
                    ..........
                  }
             }
            public static  void ProcessMessage(ReportLocation message){
                  if(message !=null){
                    ..........
                  }
             }
           public static void ProcessMessage(RequestService message){
                  if(message !=null){
                    ..........
                  }
             }
    }

     class Program
        {
            static void Main(string[] args)
            {
                List<Message> msgList = new List<Message> { new Alarm(),new ReportLocation(),new RequestService() };
                foreach (Message msg in msgList)
                {
                    string msgType = "";
                    if (msg is Alarm)
                        MessageHandle.ProcessMessage((Alarm)msg);
                    else if (msg is ReportLocation)
                         MessageHandle.ProcessMessage((ReportLocation)msg);
                    else
                     MessageHandle.ProcessMessage((RequestService )msg);
                }
            }
        }

    • 已標示為解答 宙斯 2010年3月8日 上午 07:11
    2010年3月8日 上午 06:26
  • 感謝您的回覆,試著執行了您提供的例子,測試了一下,我的理解是,經過
     if
     (msg is
     Alarm)
    確定msg的型別為Alarm 後,便可以將msg強制轉型為Alarm型別,來取出所須要的資料
    使用例如下:

    ((Alarm)msg).AlarmType = 0
    ((RequestService)msg).serviceType = 1

    另外,原本小弟想到的判斷型別方式只有
    msg.GetType().ToString() == "<namespace名稱>.<class名稱>"
    沒想到msg就直接是class本身

     不知道您的意思是否就是,判斷得知訊息的type後,再將訊息內容強制轉型為該型別,並取出對應欄位值?
    2010年3月8日 上午 06:50
  • 抱歉剛才只看到蹂躪 <abbr class="affil">兄的回覆,</abbr> 好說 兄的回覆中已提示了取出資料並轉型的部份

    但可否容小弟再提一個疑問,List在宣告時的基礎型別Message,應該表示msgList裡面放的應該是Message type的變數,可這樣使用是否是因為Alarm、ReportLocation、RequestService是繼承自Message?

    List感覺上應該只能動態擴充自己的長度,在宣告規定完型別後,為何還能加入其它型別的element?

    List<Message> msgList = new List<Message> { new Alarm(),new ReportLocation(),new RequestService() };
    2010年3月8日 上午 07:25
  • Hi,

    是~

    請參考
    物件和集合初始設定式 (C# 程式設計手冊)

    謙卑學習,持之以恆,才能不斷的Level Up http://www.dotblogs.com.tw/larrynung/
    2010年3月8日 上午 07:37
  • 這問題可以透過物件導向中的Command樣式來處理

     
    interface IMessageCommand
    {
    void Do();
    }
    
      abstract class Message : IMessageCommand
        {
            public int clientID;
            public abstract void Do();
        }
    
        class Alarm : Message
        {
            public int AlarmType;
            public override void Do()
    {
    ...實作
    }
        }
    
        class ReportLocation : Message
        {
            public string address;
            public override void Do()
    {
    ...實作
    }
        }
    
        class RequestService : Message
        {
            public int serviceType;
            public string address;
            public override void Do()
    {
    ...實作
    }
        }
    
    
    程式
    void OnMeesageReceived(Message msg)
    {
    msg.Do();
    }
    2010年3月9日 上午 01:45
  • programlin兄的建議能夠不必知道frame的型別,直接執行對應的動作,的確是相當方便,不過message本身是否適合當動作的主體,可能要再考慮一下,因為直覺上來看,message似乎不會自己執行動作

    感謝您提供的這個想法,小弟以前不常用到繼承,所以沒有想過類似的做法,以後遇到問題後應該能有多些想法
    2010年3月9日 上午 11:17
  • Message的DO方法不一定是真正的實作,也可以是利用反射的動態型別字串,這樣就會跟實作分離.
    2010年3月9日 下午 11:42