2012-07-06 49 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