2012-01-10 107 views
4

我創建一個通用的接口命令模式工作:C#泛型接口上

public interface IGenericComponent<T> where T : IVisitableObject 
{ 
    void Update(T msg); 
} 

然後,我將有另一個類,我會抱着一堆此接口的實現(各一與它自己的類型)。有有我的字典把命令列表來執行這樣的:

private Dictionary<MessageType, List<IGenericComponent>> _components; 

這會產生一個編譯錯誤,因爲我不把對IGenericComponent類型。我有一個調用Update方法和認購(以字典INSERTA的成分)的方法的線程:

public void Subscribe<T>(MessageType messageType, IGenericComponent<T> component) where T : IVisitableObject, new() 
    { 
     lock (_monitorDictionary) 
     { 
      List<IGenericComponent> subscribedList; 
      if (_components.TryGetValue(messageType, out subscribedList)) 
      { 
       subscribedList.Add(component); 
       IVisitableObject firstUpdate; 
       if(_messageBuffer.TryGetValue(messageType, out firstUpdate)) 
        component.Update((T)firstUpdate); 
      } 
      else 
      { 
       subscribedList = new List<IGenericComponent>(); 
       subscribedList.Add(component); 
       _components[messageType] = subscribedList; 
      } 
     } 
    } 

    private void ProcessQueue() 
    { 
     while (true) 
     { 
      IVisitableObject msg; 
      lock (_monitorQueue) 
      { 
       msg = _queue.Dequeue(); 
      } 
      List<IGenericComponent> components; 
      lock(_monitorDictionary) 
      { 
       components = _components[msg.MsgType]; 
      } 
      if(components!= null) 
      { 
       foreach (IGenericComponent genericComponent in components) 
        genericComponent.Update(msg); 
      } 
     } 
    } 

此代碼不能編譯... 我從Java編程來,在Java中,我可以當我實例化類型時,省略參數化類型。所以...我想知道是否有可能在C#中做到這一點,所以它會假設它是泛型類型(IVisitableObject)。或者,如果你知道解決這個問題的更好方法... 我解決這個問題的方式並不是我想要的方式。我從界面中刪除了泛型,並使用泛型類型IVisitableObject作爲Update方法的參數。 在此先感謝。

+0

Java的泛型與.NET完全不同。在Java中,泛型只是一些元數據和一些編譯器糖,以便在編譯時檢查類型安全性,並在必要時發出類型轉換(「擦除」)。但是,在.NET中,每個泛型類型在運行時都是作爲自己的類型構建的;他們就好像你已經寫了特定類型的代碼一樣,這就是爲什麼他們也爲值類型和原語工作的原因(例如'字典'等不包含鍵或值)。 – Lucero 2012-01-10 18:41:15

回答

2

我用在傑森的回答方法,它工作正常,特別是如果你可以隱藏IVisitableObject在基類的強制轉換爲T。但是如果你想避免強制類來實現非泛型接口,你可以使用這種模式。將您的訂戶存儲爲List<object>並使用幫助程序類(Dispatcher)發送消息。

public interface IVisitableObject { } 
public interface IGenericComponent<T> where T : IVisitableObject 
{ 
    void Update(T msg); 
} 

abstract class Dispatcher 
{ 
    protected Dispatcher() { } 

    public abstract void Dispatch(IVisitableObject message, IEnumerable<object> subscribers); 


    static Dictionary<Type, Dispatcher> dispatchers = new Dictionary<Type, Dispatcher>(); 

    static Dispatcher GetDispatcherFor(IVisitableObject message) 
    { 
     Type type = message.GetType(); 

     if (!dispatchers.ContainsKey(type)) 
     { 
      Type closedType = typeof(Dispatcher<>).MakeGenericType(message.GetType()); 
      object dispatcher = Activator.CreateInstance(closedType); 
      dispatchers[type] = (Dispatcher)dispatcher; 
     } 

     return dispatchers[type]; 
    } 
} 

class Dispatcher<T> : Dispatcher where T : IVisitableObject 
{ 
    public override void Dispatch(IVisitableObject message, IEnumerable<object> subscribers) 
    { 
     var msg = (T)message; 
     foreach (var subscriber in subscribers.OfType<IGenericComponent<T>>()) 
     { 
      subscriber.Update(msg); 
     } 
    } 
} 
+0

工作就像一個魅力!謝謝你和@Jason :) – Augusto 2012-01-11 11:55:45

+0

哦,我應該這樣調用它: Dispatcher.GetDispatcherFor(msg).Dispatch(msg,components); 對不對? – Augusto 2012-01-11 11:57:20

+0

這是正確的。 – 2012-01-11 15:38:20

3

最簡單的辦法就是

interface IGenericComponent { 
    void Update(IVisitableObject msg); 
} 
interface IGenericComponent<T> : IGenericComponent where T : IVisitableObject { 
    void Update(T msg); 
} 
+0

@Gene C:你說得對。 – jason 2012-01-10 18:36:08

+0

@GeneC它是一個接口。 – Augusto 2012-01-10 18:52:32

+0

@Jason第一個建議是我現在使用的建議,但如果可能,我想使用泛型。第二個不編譯 – Augusto 2012-01-10 18:53:41