2

我正在尝试将这个动态双重调度示例移植到 C#。我已经完成了这个示例,但我觉得我已经通过使用反射来创建所需的处理程序并调用适当的方法来简化类DynamicDispatch中的方法。MessageBase任何人都可以就如何更改它提供一些建议吗?该示例使用 C++ dynamic_cast 运算符,我不确定 C# 的等价物是什么。我不确定我的解决方案是正确/最好的方法。

注意:我使用的是 3.5,所以我不能使用动态关键字

这是代码:

即时消息

public interface IMessage
{
   void Dispatch(IHandler handler);
}

消息库

public abstract class MessageBase : IMessage
{
   public abstract void Dispatch(IHandler handler);

   // This is my concern, doesnt feel like the right way to do this
   protected void DynamicDispatch<MessageType>(IHandler handler, MessageType self)
   {
      // Get the messages derived type
      Type self_type = self.GetType();   
      // Create actual message specific handler
      Type message_handler = typeof(IMessageHandler<>).MakeGenericType(self_type);
      // Get the ProcessMessage method
      MethodInfo minfo = message_handler.GetMethod("ProcessMessage");
      try
      {
         // Invoke it with the message
         minfo.Invoke(handler, new object[] { self });
      }
      catch (TargetException ex)
      {
         // Ignore if method doesnt exist
      }
   }
}

信息

public class Message : MessageBase
{
   public override void Dispatch(IHandler handler)
   {
      DynamicDispatch(handler, this);
   }
}

处理程序

public interface IHandler
{
}

消息处理程序

public interface IMessageHandler<MessageType> : IHandler
{
   void ProcessMessage(MessageType message);
}

派生消息一

public class DerivedMessageOne : Message
{
   public int MessageOneField;
}

派生消息二

public class DerivedMessageTwo : Message
{
   public int MessageTwoField;
}

DerivedMessageHandlerOne

public class DerivedMessageHandlerOne : IMessageHandler<DerivedMessageOne>,
   IMessageHandler<DerivedMessageTwo>
{
   #region IMessageHandler<MessaegType> Members

   // ************ handle both messages *************** //
   public void ProcessMessage(DerivedMessageOne message)
   {
      // Received Message one, do soemthing with i
      int do_something_with_it = message.MessageOneField;
   } 

   public void ProcessMessage(DerivedMessageTwo message)
   {
      // Received Message two, do soemthing with i
   } 

   #endregion
}

DerivedMessageHandlerTwo

public class DerivedMessageHandlerTwo : IMessageHandler<DerivedMessageOne>
{
   #region IMessageHandler<MessaegType> Members

   // ************ handle just MessageOne *************** //
   public void ProcessMessage(DerivedMessageOne message)
   {
      // Received Message one, do soemthing with i
   }

   #endregion
}

测试用例

IMessage messageOne = new DerivedMessageOne();
IMessage messageTwo = new DerivedMessageTwo();
IHandler handlerOne = new DerivedMessageHandlerOne();
IHandler handlerTwo = new DerivedMessageHandlerTwo();

messageOne.Dispatch(handlerOne);
messageOne.Dispatch(handlerTwo);

messageTwo.Dispatch(handlerOne);
messageTwo.Dispatch(handlerTwo);
4

2 回答 2

2

在 C# 中,您需要as运算符。 http://msdn.microsoft.com/en-us/library/vstudio/cscsdfbt.aspx

它的行为与 C++ 完全相同dynamic_cast

在这里它会被用来:

IMessageHandler<MessageType> handlerTarget = handler as IMessageHandler<MessageType>;
handlerTarget.ProcessMessage(message);

正如您所指出的,您必须将消息类型传递到消息库中,例如:

class MessageBase
{
    protected void DoDispatch<T>(T m)
    {
        // ...
    }
}
class Message<T> : MessageBase where T : class
{
    public void Dispatch()
    {
        DoDispatch<T>(this as T);
    }
}
class MyMessage : Message<MyMessage>
{
}
于 2013-03-28T16:31:16.573 回答
0

我发现这个 DoubleDispatch 在没有动态的情况下可以正常工作:

namespace DoubleDispatch
{
public interface IMessage
{
    void Dispatch(HandlerBase handler);
}

public interface IHandler
{
    void HandleDefault(IMessage message);
}

public interface IHandler<in TMessage> : IHandler
    where TMessage : class, IMessage
{
    void HandleSpecific(TMessage message);
}

public interface IMessage<TMessage, THandler> : IMessage
    where TMessage : class, IMessage<TMessage, THandler>
    where THandler : class, IHandler<TMessage>
{
}

public abstract class HandlerBase : IHandler
{
    public void HandleDefault(IMessage message)
    {
        Console.WriteLine("HandlerBase process {0}", message.GetType().Name);
    }
}

public abstract class MessageBase<TMessage, THandler>
    : IMessage<TMessage, IHandler<TMessage>>
    where TMessage : class, IMessage, IMessage<TMessage, IHandler<TMessage>>
    where THandler : class, IHandler, IHandler<TMessage>
{
    public void Dispatch(HandlerBase handler)
    {
        var runtimeHandler = handler as THandler;
        if (runtimeHandler != null)
        {
            var runtimeMessage = this as TMessage;
            if (runtimeMessage != null)
            {
                runtimeHandler.HandleSpecific(runtimeMessage);
                return;
            }
        }
        handler.HandleDefault(this);
    }
}

public class FirstMessage : MessageBase<FirstMessage, IHandler<FirstMessage>>
{
}

public class SecondMessage : MessageBase<SecondMessage, IHandler<SecondMessage>>
{
}

public class FirstHandler : HandlerBase, IHandler<FirstMessage>
{
    public void HandleSpecific(FirstMessage message)
    {
        Console.WriteLine("FirstHandler process {0}", message.GetType().Name);
    }
}

public class SecondHandler : HandlerBase, IHandler<SecondMessage>
{
    public void HandleSpecific(SecondMessage message)
    {
        Console.WriteLine("SecondHandler process {0}", message.GetType().Name);
    }
}

public class ThirdHandler : HandlerBase, IHandler<FirstMessage>, IHandler<SecondMessage>
{
    public void HandleSpecific(FirstMessage message)
    {
        Console.WriteLine("ThirdHandler process {0}", message.GetType().Name);
    }

    public void HandleSpecific(SecondMessage message)
    {
        Console.WriteLine("ThirdHandler process {0}", message.GetType().Name);
    }
}

public class EmptyHandler : HandlerBase
{
}

public static class DoubleDispatch
{
    public static void Test()
    {
        var handlers = new HandlerBase[]
        {
            new FirstHandler(),
            new SecondHandler(),
            new ThirdHandler(), 
            new EmptyHandler(), 
        };

        var messages = new IMessage[]
        {
            new FirstMessage(),
            new SecondMessage(), 
        };

        Array.ForEach(messages, m =>
        {
            Array.ForEach(handlers, m.Dispatch);
            Console.WriteLine();
        });
    }
}
}
于 2014-11-02T10:57:00.680 回答