2012-03-30 59 views
3

我用我的代碼遇到了一點設計問題。 我有一個對象創建一個子對象(然後孩子可以創建另一個子對象等),並且這兩個對象都訂閱相同的事件。 但是,我只想要最多的子對象接收事件。如何讓只有最遠的孩子接受共享事件?

我的項目是什麼概述: 我正在創建一個IVR系統。當用戶調用系統時,用戶將擁有X菜單選項。根據用戶選擇的內容,他們將有一個選擇子菜單,依此類推等等。我正在使用狀態機。當用戶在手機上按下號碼時,每臺狀態機都需要「監聽」。但是隻有當前的狀態機需要處理輸入的數字。每個狀態機都可以創建一個新的狀態機來表示子菜單。

下面是一些示例代碼:

基類:

public delegate void DoSomething(object sender, EventArgs data); 
public class Base 
{ 
    public event DoSomething myEvent; 
    private IObject foo; 

    public Base() 
    { 
     foo = new myObjectA(this); 
    } 

    public void SomeAction() 
    { 
     ((myObjectA)foo).CreateChild(); 
    } 

    public void EventFired() 
    { 
     if (myEvent != null) 
     { 
      myEvent(this, new EventArgs()); 
     } 
    } 
} 

對象A:

class myObjectA : IObject 
{ 
    private Base theCallingObject; 
    private IObject child; 
    public myObjectA (Base _base) 
    { 
     theCallingObject = _base; 
     theCallingObject.myEvent += new DoSomething(theCallingObject_myEvent); 
    } 

    public void CreateChild() 
    { 
     child = new myObjectB(theCallingObject); 
    } 

    void theCallingObject_myEvent(object sender, EventArgs data) 
    { 
     // Handle event 
     MessageBox.Show("myObjectA"); 
    } 
} 

對象B:

class myObjectB : IObject 
{ 
    private Base theCallingObject; 
    public myObjectB (Base _base) 
    { 
     theCallingObject = _base; 
     theCallingObject.myEvent += new DoSomething(theCallingObject_myEvent); 
    } 

    void theCallingObject_myEvent(object sender, EventArgs data) 
    { 
     // Handle event 
     MessageBox.Show("myObjectB"); 
    } 
} 

現在,當我這樣做:

Base blah = new Base(); 
blah.SomeAction(); 
blah.EventFired(); 

我得到A和B的消息框。 我需要實現Base以便只有myObjectB才能獲取事件。 我將擁有數百個myObject,所以我需要一個基本級別的實現,而不是myObject級別。另外,如果有數百個對象,則在myObject級別處理它仍然需要觸發事件,導致性能問題。

我考慮過的一種解決方案是,當myObjectA創建子項時,取消訂閱該事件,然後在返回myObjectA級別時重新訂閱。但是我覺得可以做更好的事情。

任何人有任何想法?

編輯:使用payo輸入我想出了這一點:

public delegate void DoSomething(object sender, EventArgs data); 
public class Base 
{ 
    private IObject foo; 
    private List<DoSomething> _myEventStorage; 

    public event DoSomething myEvent 
    { 
     add 
     { 
      _myEventStorage.Insert(0, value); 
     } 
     remove 
     { 
      _myEventStorage.Remove(value); 
     } 
    } 

    public Base() 
    { 
     _myEventStorage = new List<DoSomething>(); 
     foo = new myObjectA(this); 
    } 

    public void SomeAction() 
    { 
     ((myObjectA)foo).CreateChild(); 
    } 

    public void EventFired() 
    { 
     _myEventStorage[0].Invoke(this, new EventArgs()); 
    } 
} 
+0

而不是狀態機,你可以實現這個線程(或新的C#5異步的東西),等待按鈕被按下? – Random832 2012-03-30 19:14:45

+0

@ Random832我不太明白你想說什麼。但是,爲每個呼叫單獨分配一個呼叫將是不可行的,因爲在任何情況下都可以有多達100個呼叫活動,並且上下文切換將開始達到性能。 – jpiccolo 2012-03-30 19:23:58

回答

1

對於事件,每個用戶都排隊(放在列表的末尾),一個FIFO模型。您希望最孩子的對象「擁有」事件,而不僅僅是訂閱併成爲其他未知對象的抽象列表的一部分。

我會提供一個新的模型,表示你正在嘗試做什麼。這可能是傑森推薦的:(他發佈他的答案,因爲我輸入了這個)

public class Base 
{ 
    private DoSomething _myEventStorage; 
    public event DoSomething myEvent 
    { 
    add 
    { 
     _myEventStorage = value; 
    } 
    remove 
    { 
     _myEventStorage -= value; 
    } 
    } 
... 
    public void EventFired() 
    { 
    if (_myEventStorage != null) 
    { 
     _myEventStorage(this, new ChainEventArgs()); 
    } 
    } 
} 

這只是最後一次調用。另一種選擇(添加到這個自定義添加/刪除),將提供一個派生的EventArgs:

public class ChainEventArgs : EventArgs 
{ 
    public bool Handled { get; set; } 
} 
public delegate void DoSomething(object sender, ChainEventArgs data); 

... 

    public event DoSomething myEvent 
    { 
    add 
    { 
     var temp = _myEventStorage; 
     _myEventStorage = null; 
     _myEventStorage += value; 
     _myEventStorage += temp; // now all are called, but FILO 
    } 
    remove 
    { 
     _myEventStorage -= value; 
    } 
    } 

在這一點上,你可以在每個IObject提取檢查Handled

void theCallingObject_myEvent(object sender, ChainEventArgs data) 
{ 
    if (data.Handled) 
    return; 

    if (I_want_to_block_parents) 
    data.Handled = true; 
    // else leave it false 
} 

或者,添加一些複雜到你的基類,並停止調用鏈(讓我們的孩子們無需檢查Handled)。我將使用代表的名單顯示解決方案,但是一些MulticaseDelegate轉換和調用可以執行相同的操作。我只是覺得List <>代碼可能更易讀/可維護。

public class Base 
{ 
    private List<DoSomething> _myEventStorage; 
    public event DoSomething myEvent 
    { 
    add 
    { 
     _myEventStorage.Insert(0, value); 
    } 
    remove 
    { 
     _myEventStorage.Remove(value); 
    } 
    } 
... 
    public void EventFired() 
    { 
    var args = new ChainEventArgs(); 
    foreach (var handler in _myEventStorage) 
    { 
     handler(this, args); 
     if (args.Handled) 
     break; 
    } 
    } 
} 
+0

偉大的解決方案! – jpiccolo 2012-03-30 21:00:54

2

你需要明確落實myEvent(添加/刪除)處理和跟蹤的「最遠」獨立註冊的觀察員。那麼您可以將通知發送到該單個實例。

相關問題