2015-10-17 52 views
1

我一直在開發一些遊戲的不同事件系統,其中偵聽器接收到通用事件類型對象,並且必須將其真實類型與開關或類似對象進行區分,然後將其轉換爲正確的子類事件。字典上的C#代表的逆變問題

不同aproaches我能後襬脫使用結構的開關情況如下(簡化):

public class Event {} 
public class EventA : Event {} 
public class EventB : Event {} 

public delegate void HanlderDelegate(Event ev); 

public class EventManager 
{ 
    Dictionary<Type, HanlderDelegate> delegateMap = new Dictionary<Type, HanlderDelegate>(); 

    public void Dispatch(Event ev) 
    { 
     if (delegateMap.ContainsKey(ev.GetType())) 
     { 
      delegateMap[ev.GetType()].Invoke(ev); 
     } 
    } 

    public void Register<T>(HanlderDelegate handler) where T : Event 
    { 
     delegateMap.Add(typeof(T), handler); 
    } 
} 

public class EventListener 
{ 
    public EventListener(EventManager evtMgr) 
    { 
     evtMgr.Register<EventA>(this.HandleEventA); 
     evtMgr.Register<EventB>(this.HandleEventB); 
    } 

    public void HandleEventA(Event ev) 
    { 
     EventA evA = (EventA)ev; 
     //... do stuff 
    } 

    public void HandleEventB(Event ev) 
    { 
     EventB evB = (EventB)ev; 
     //... do stuff 
    } 
} 

我這種做法很高興,但我還是找到了鑄件每種方法都可以改進。我試圖讓代表更通用

public delegate void HanlderDelegate<T>(T ev) where T : Event;因此聽衆可以直接執行public void HandleEvent(EventA ev)public void HandleEvent(EventB ev)並註冊它們。
但是,當然,EventManager類中的字典應該存儲指向HanlderDelegate<Event>的指針,並且存在問題開始的地方,我不能將HanlderDelegate<EventA>轉換爲HanlderDelegate<Event>以存儲它們,並且同時以另一種方式調用它以調用它們。

有沒有辦法做到這一點?我知道編譯器會允許奇怪的東西,但是我知道它,並且可以通過代碼控制EventB沒有被錯誤地輸出到EventA等等。
在此先感謝!

回答

0

你可以做委託和Dispatch方法通用,並存儲處理程序爲Delegate而非HandlerDelegate<T>

delegate void HandlerDelegate<TEvent>(TEvent ev) where TEvent : Event; 

class EventManager 
{ 
    Dictionary<Type, Delegate> delegateMap = new Dictionary<Type, Delegate>(); 

    public void Dispatch<TEvent>(TEvent ev) where TEvent : Event 
    { 
     Delegate d; 
     if (delegateMap.TryGetValue(typeof(TEvent), out d)) 
     { 
      var handler = (HandlerDelegate<TEvent>)d; 
      handler(ev); 
     } 
    } 

    public void Register<TEvent>(HandlerDelegate<TEvent> handler) where TEvent : Event 
    { 
     delegateMap.Add(typeof(TEvent), handler); 
    } 
} 

當然,你仍然有在Dispatch方法來投,但在這一點上你知道演員是正確的。

+0

謝謝,托馬斯!在字典中使用類型委託允許代表是通用的並解決該部分。從來沒有遇到過。我也注意到Delegate類可以調用DynamicInvoke而不需要強制轉換。有沒有什麼區別,比如表演等等?因爲設置Dispatch方法通用限制了可能性,例如在分派所有事件之前排隊所有事件。 –