2012-07-06 75 views
1

如何在運行時將基類轉換爲派生類。 我想要做的是以下幾點:我需要一個系統,將持有的訂閱, 某些類型的消息,有一個分配的訂閱者。當收到一條消息時,它將被轉發到這個系統,如果有這種消息的任何訂閱者,它將進行查找,如果是的話,消息被轉發給訂閱者。我有一個叫做Response的抽象基類,接下來是一個抽象層,例如。 AFResponse:響應,然後有實際的(具體的)實現,例如。 回覆(摘要):AFResponse(摘要):AFIncommingMessage(具體)。在運行時動態解析並將基類轉換爲派生類型

當接收到分組時,它前進到MessageBuilder,它解決了消息類型和建立的話,像這樣:

public static T Build<T>(Packet packet) where T : Response 
{ 
    Type resolvedType; 
    if (!dependencyMap.TryGetValue(packet.MessageId, out resolvedType)) 
    { 
     var str = String.Format("Could not resolve message. Message info: CMD0: {0}, CMD1: {1}, MessageID: {2}", 
           packet.Cmd0, packet.Cmd1, packet.MessageId); 
     Debug.WriteLine(str); 

     throw new ResolutionFailedException(str); 
    } 

    ConstructorInfo firstConstructor = resolvedType.GetConstructors().First(); 

    return (T) firstConstructor.Invoke(new object[] {packet}); 
} 

然後,如果消息被異步,它被轉發到MessageBinder,持有訂閱的消息類型。

private void OnAsyncResponseReceived(Response response) 
{ 
    messageBinder.Forward(response); 
} 

而一個MessageBinder類被實現爲以下:

public class MessageBinder 
{ 
    private class Subscriber<T> : IEquatable<Subscriber<T>> where T : Response 
    { 
     ... 
    } 

    private readonly Dictionary<Type, IEnumerable> bindings; 

    public MessageBinder() 
    { 
     this.bindings = new Dictionary<Type, IEnumerable>(); 
    } 

    public void Bind<TResponse>(ushort shortAddress, Action<ZigbeeAsyncResponse<TResponse>> callback) 
     where TResponse : Response 
    { 
     HashSet<Subscriber<TResponse>> subscribers = this.GetSubscribers<TResponse>(); 
     if (subscribers != null) 
     { 
      subscribers.Add(new Subscriber<TResponse>(shortAddress, callback)); 
     } 
     else 
     { 
      var subscriber = new Subscriber<TResponse>(shortAddress, callback); 
      this.bindings.Add(typeof(TResponse), new HashSet<Subscriber<TResponse>> { subscriber }); 
     } 
    } 

    public void Forward<TResponse>(TResponse response) 
     where TResponse : Response 
    { 
     var subscribers = this.GetSubscribers<TResponse>(); 
     if (subscribers != null) 
     { 
      Subscriber<TResponse> subscriber; 

      var afResponse = response as AFResponse; 
      if (afResponse != null) 
      { 
       subscriber = subscribers.SingleOrDefault(s => s.ShortAddress == afResponse.ShortAddress); 
      } 
      else 
      { 
       subscriber = subscribers.FirstOrDefault(); 
      } 

      if (subscriber != null) 
      { 
       Debug.WriteLine("Forwarding received async response of type " + response.GetType().Name); 
       subscriber.Forward(response); 
      } 
     } 
    } 

    private HashSet<Subscriber<TResponse>> GetSubscribers<TResponse>() where TResponse : Response 
    { 
     IEnumerable subscribers; 
     this.bindings.TryGetValue(typeof(TResponse), out subscribers); 

     return (HashSet<Subscriber<TResponse>>)subscribers; 
    } 
} 

,就會出現問題,當MessageBinder類的()的方法GetSubscribers被調用時,因爲τ響應的類型是類型基類的,這是響應,因此沒有找到用戶。所以我認爲我需要做的是以某種方式將實際類型的消息傳遞給Forward方法,以便該類型成爲實際的響應類型。

我改變,像這樣的方法:

private void OnAsyncResponseReceived(Response response) 
{ 
    messageBinder.Forward((dynamic)response); 
} 

它的工作,但不知何故,我的事情有一個更好的辦法做到這一點?或者這是實際的和唯一的解決辦法(?)?也許我應該改變整體設計,我不知道......我第一次面對這類問題,這就是我想出的。

我很樂意接受建議,評論家,當然,最好的解決方案:) 我很好奇,如果它不同於我的解決方案並且效率更高,那麼您將如何實現此目標。 謝謝你的幫助!

+0

從小孩投給父母很容易,但是父母對小孩是不可能的。例如,將文本框轉換爲控件是可能的,但對文本框的控制是不可能的。 – 2012-07-06 11:28:48

+0

@NikhilAgrawal:你的意思是不可能投射到派生類? – 2012-07-06 11:43:23

+0

隱含號碼明確表示是。閱讀本http://stackoverflow.com/questions/124336/a-way-of-casting-a-base-type-to-a-derived-type – 2012-07-06 11:48:35

回答

1

您是否考慮過通過消息本身路由對訂閱者的請求?它不一定需要是直接的 - 你的基類可能需要子類來覆蓋暴露某種實用對象的屬性。該實用程序對象可以強類型化爲消息類型,並且可以進行強類型的調用來獲取訂閱者。

您仍然可以使用您創建的方法(用於提取訂閱者) - 實用程序類只能夠進行強類型化的調用。

編輯:

這個怎麼樣?

private void OnAsyncResponseReceived<T>(T response) where T : Response { 
    messageBinder.Forward(response); 
} 

原始代碼的問題是響應變量是強類型的。投射到動態的「非強類型」它。通過使用泛型方法,就像在整個應用程序中所做的那樣,使用泛型類型必須從Response繼承的附加約束,您將得到與使用內置動態類型相同的結果的效果。老實說,我認爲投射到動態是相當聰明的。:)

+0

這確實可行......沒有想到這一點。謝謝你的提示!但這是處理這類問題的唯一方法,還是有辦法更有效地設計這種方法嗎? – DavorinP 2012-07-06 20:16:51

+0

@pajci - 更新了答案 – JDB 2012-07-06 22:06:14