2012-03-08 147 views
4

有沒有辦法指定處理註冊事件代表的順序或優先級?例如,我有一個事件需要在任何其他事件之前立即處理,但我希望其他對象也可以註冊事件的偵聽器。這如何實現?事件優先級和流程訂單

可以說,我想PROC1總是PROC之前這樣做的運行2.

class MessageProcessor 
{ 
    private DataClient Client; 
    public MessageProcesser(DataClient dc) 
    { 
     Client = dc; 
     Client.MessageReceived += ProcessMessage; 
    } 

    void proc1(MessageEventArgs e) 
    { 
     // Process Message 
    } 

} 

class DataClient 
{ 
    public event MessageReceievedHandler MessageReceived; 
} 

void main() 
{ 
    DataClient dc = new DataClient(); 
    MessageProcessor syncProcessor = new MessageProcessor(dc); // This one is high priority and needs to process all sync immediately when they arrive before any data messages 
    MessageProcessor dataProcessor= new MessageProcessor(dc); // This one can process the data as it has time when sync messages are not being processed. 

    // do other stuff 

} 

的原因,我有一個是通過UDP流發送郵件的服務器。它會在突發數據前發送同步消息。我意識到這兩個處理程序會在收到同步消息時觸發,但爲了減少延遲,我希望在dataProcessor事件之前處理syncProcessor對象事件。這將減少正在處理的同步消息的延遲。

另外,我的團隊中的其他人也可能想要註冊事件來處理特定的消息。他們可能有自己的對象來註冊一個事件(可能不是MessageProcessor),即使同步消息應該儘可能的延遲。

編輯用更好的例子使目標更清晰。

+0

在處理程序中排隊MessageEventArgs,然後啓動一個實現優先級和依賴性的方法。這是你知道的一個bugfest,在我試圖不經常失敗之前,我會與自己進行激烈的對話。 – 2012-03-08 18:34:27

+0

我只是爲了簡單起見,因爲我認識到在這種情況下注冊同一資源/對象內的兩個事件都是毫無意義的。我會更改我的設置以更準確地表示我的目標。 – galford13x 2012-03-08 18:34:58

+0

@Tony:有趣的想法。我同意這可能會進入一個問題領域。我實際上正在考慮創建一個接口,當有人註冊一個事件時,DataClient會註冊它,但有一個優先級映射對象,當收到一條消息時它會按照定義的順序關閉處理程序中的事件。但這似乎也是一個不好的道路。 – galford13x 2012-03-08 18:37:46

回答

0

我要出去一個肢體,說不。 AFAIK事件本質上是異步調度的。所以會按照他們綁定的順序發送。但結果可能會以不同的順序返回。唯一的方法是在第一個事件的回調中派發第二個事件。這不是特定於語言的,更多的是關於事件的架構。

在你的例子中,因爲調用是void,所以不要在proc1的末尾運行proc2?

+1

事件是異步調度的?我認爲他們都是在同一個線程上發送的,當然這會讓它們同步。我假定你的意思是他們沒有按照定義的順序發送?如果他們總是按照他們綁定的順序發送,那麼我可以通過確保首先註冊最高優先級的事件來實現我的目標? – galford13x 2012-03-08 18:52:01

+0

所以你說整個線程在事件發送時睡覺?如果沒有什麼事情必然會發生。該應用程序將無限期地等待。這就是爲什麼我認爲它在那個時候是異步的?沒有? – 2012-03-08 23:36:57

+0

如果你需要它同步發生,你應該從函數1調用函數2,其中函數1是事件處理函數。否則,你將創造一個競賽條件。這就是世界上每個其他事件模型的存在方式。我對它的工作方式有99%的肯定C# – 2012-03-08 23:40:31

1

在這種情況下,你最好只是要求在第一次活動結束的第二個事件,等等

0

如果這是你定義的,那麼你最好的選擇可能是把它擴大自己的事件有一個BeforeMessageReceived,MessageReceived和AfterMessageReceived事件。 (好吧,也許MessageProcessed會是一個更好的根,因爲你可以在之前知道)。

這將使您更精確地掌握不同事件處理程序發生的位置。

看到相同事件,所有的地方彭定康。

5

當您多次訂閱一個事件時,在觸發事件時,無法確定處理程序的執行順序。

根據this answer,訂購訂單中的訂單,但正如帖子作者所說,這是一個實施細節,您不能依賴它。

你當然可以編寫你自己的「事件管理器」(見下面的髒例子),它以已知的順序執行你的處理程序,但我認爲這不是一個好主意。也許你應該重新設計你的活動來消除你的需求。

public class MyClass 
{  
    // Could be anything... 
    public delegate void MyEventHandler(object sender, EventArgs e); 

    public event MyEventHandler TestEvent; 

    public void Test() 
    { 
     if (this.TestEvent != null) 
     { 
      this.TestEvent(this, EventArgs.Empty); 
     } 
    } 
} 

public class EventManager 
{ 
    private List<EventHandler> Handlers = new List<EventHandler>(); 

    public void AddHandler(EventHandler handler) 
    { 
     this.Handlers.Add(handler); 
    } 

    public void RemoveHandler(EventHandler handler) 
    { 
     this.Handlers.Remove(handler); 
    } 

    public void Handler(object sender, EventArgs e) 
    { 
     foreach (var z in this.Handlers) 
     { 
      z.Invoke(sender, e); 
     } 
    } 
} 

private static void Main(string[] args) 
{ 
    MyClass test = new MyClass(); 

    EventManager eventManager = new EventManager(); 

    // Subscribes to the event 
    test.TestEvent += eventManager.Handler; 

    // Adds two handlers in a known order 
    eventManager.AddHandler(Handler1); 
    eventManager.AddHandler(Handler2); 

    test.Test(); 

    Console.ReadKey(); 
} 

private static void Handler1(object sender, EventArgs e) 
{ 
    Console.WriteLine("1"); 
} 

private static void Handler2(object sender, EventArgs e) 
{ 
    Console.WriteLine("2"); 
} 
+0

+1:這個例子與我打算做的相似。但我也認爲這是一條不好的道路。我正在瞄準內置於.net的解決方案。 – galford13x 2012-03-08 18:50:05